/* * main.cpp * * Created on: Nov 2, 2015 * Author: Philipp Hinz */ #include #include #include #include #include #include #include #include #include #include #include "global.h" #include "timer.h" #include "database.h" #include "logger.h" #include "lcd.h" #include "hal.h" #include "stripe.h" #include "coffee.h" #include "display.h" #include "server.h" #include "events.h" #include "DS18B20.h" const int buildno = (1+(int)( #include "buildno" )); int verbose = 0; bool optDate = false; bool optPower = false; bool optNoNet = false; void *mainLoop(void *threadid); void terminationHandler(int signum); void usr1Handler(int signum); void hupHandler(int signum); pthread_t thread[4]; pthread_mutex_t mutex_spi; pthread_mutex_t mutex_i2c; pthread_mutex_t mutex_logger; int main(int argc, char *argv[]) { pthread_attr_t attr; pthread_mutexattr_t mutexattr; void *status; int rc; int opt; int prev_ind; logger(V_NONE, LOG_INFO, "CoffeePi by Philipp Hinz and Sebastian Vendt - " "Build number %d\n", buildno); // Argument handling while (prev_ind = optind, (opt = getopt(argc, argv, "?hvVdpn")) != -1) { if (argc > 3) if (optind == prev_ind + 2 && *optarg == '-') { opt = '?'; --optind; } switch (opt) { case 'v': // be verbose verbose++; break; case 'V': //printf("Build number %d\n", buildno); return EXIT_SUCCESS; break; case 'd': // Print timestamp in every line optDate = true; break; case 'p': // power machine on program start optPower = true; break; case 'n': // disable network functionality optNoNet = true; break; case '?': case 'h': printf("Usage: %s [-hvVdp]\n", argv[0]); printf("\t-h\t\tPrints this help\n"); printf("\t-v\t\tSets verbose output, can be used multiple times\n"); printf("\t-V\t\tPrints only the version and exits\n"); printf("\t-d\t\tPrints a timestamp before every line\n"); printf("\t-p\t\tPowers the machine on program start\n"); printf("\t-n\t\tDisable network functionality\n"); printf("Listening to the following signals:\n"); printf("\tSIGUSR1(%u)\tPrints monitor data of all nodes\n", SIGUSR1); printf("\tSIGHUP(%u)\tRuns a speedtest starting at default speed\n", SIGHUP); return EXIT_SUCCESS; default: fprintf(stderr, "Usage: %s [-hvVdpn]\n", argv[0]); return EXIT_FAILURE; break; } } if (signal(SIGINT, terminationHandler)) { // Calls terminationHandler if SIGINT is received fprintf(stderr, "Unable to set signal handler for SIGINT: %s\n", strerror(errno)); } if (signal(SIGUSR1, usr1Handler)) { // Calls terminationHandler if SIGINT is received fprintf(stderr, "Unable to set signal handler for SIGUSR1: %s\n", strerror(errno)); } if (signal(SIGHUP, hupHandler)) { // Calls terminationHandler if SIGINT is received fprintf(stderr, "Unable to set signal handler for SIGHUP: %s\n", strerror(errno)); } // sets up the wiringPi library if (wiringPiSetup() < 0) { fprintf(stderr, "Unable to setup wiringPi: %s\n", strerror(errno)); return 1; } logger_reset(); initTimers(); sqlOpen(); sqlSetup(); displayInit(); //temperatur_init(); DS18B20_init(); // http://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm // Initialize and set thread joinable pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); rc = pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP); if (rc != 0) throw(L"pthread_mutexattr_settype returns " + rc); pthread_mutex_init(&mutex_spi, &mutexattr); pthread_mutex_init(&mutex_i2c, &mutexattr); pthread_mutex_init(&mutex_logger, &mutexattr); rc = pthread_mutexattr_destroy(&mutexattr); if (rc != 0) throw(L"pthread_mutexattr_destroy returns " + rc); for (int i = 0; i < 5; i++) {//TODO this can be simplified! if (i == THREAD_MAIN) rc = pthread_create(&thread[i], &attr, mainLoop, (void *) i); else if (i == THREAD_STRIPE) rc = pthread_create(&thread[i], NULL, stripeThread, (void *) i); else if (i == THREAD_DISPLAY) rc = pthread_create(&thread[i], NULL, displayThread, (void *) i); else if (i == THREAD_COFFEE) rc = pthread_create(&thread[i], NULL, coffeeThread, (void *) i); else if (i == THREAD_SERVER && !optNoNet) rc = pthread_create(&thread[i], NULL, serverThread, (void *) i); if (rc) { logger_error("Error:unable to create thread %d (%d)\n", i, rc); exit(-1); } } //hal might send signals to processes which must exist! halInit(); // free attribute and wait for the other threads pthread_attr_destroy(&attr); sleep(2); rc = pthread_join(thread[0], &status); if (rc) { logger_error("Error:unable to join, %d\n", rc); exit(-1); } logger(V_BASIC, "Completed thread with status %d\n", rc); pthread_exit(NULL); return EXIT_FAILURE; } /** * Handler for program termination caught via signal */ void terminationHandler(int signum) { logger(V_NONE, "Caught signal %d, exiting gracefully..\n", signum); stopTimers(); //TODO This event is not fired anymore... event_trigger("terminate"); /*logger(V_NONE, "Saving my state to the database..\n"); sqlExecute("begin"); // Save stuff here sqlExecute("end");*/ sqlClose(); // Closing DB connection exit(EXIT_SUCCESS); } /** * Handles the signal USR2 */ void usr1Handler(int signum) { // Do something here? logger_reset(); } /** * Handles the signal HUP and starts a speed test */ void hupHandler(int signum) { // Do something here? } /** * Sends a signal to a thread * @param threadid ID of the thread * @param sig Signal to send */ void killThread(int threadid, int sig) { //logger(V_BASIC, "pthread_kill on thread %d (%d)\n", threadid, sig); if (pthread_kill(thread[threadid], sig)) { logger_error("pthread_kill on thread %d failed (%d)\n", threadid, sig); } } /** * Main Thread, used for some initializations and error detection * @param threadid Thread ID */ void *mainLoop(void *threadid) { // Do more stuff here while (1){ sleep(4); /*int8_t temp = DS18B20_readTemp(); logger(V_BASIC, "Temperature: %d\n", temp);*/ } logger(V_BASIC, "Thread goes Sleeping..\n"); while (1) { pause(); logger(V_NONE, LOG_ERROR, "Whoops. Something went wrong..\n"); } pthread_exit(NULL); }