/********************************************************************************* * Copyright: (C) 2018 LingYun IoT Studio * All rights reserved. * Filename: iotd_main.c * Description: This file is iotd (Internet of Things daemon) program main() entry point, * * Version: 1.0.0(2018/11/19) * Author: Guo Wenxue * ChangeLog: 1, Release initial version on "2018/11/19 22:05:56 CST" * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cp_proc.h" #include "iotd_conf.h" void *watchdog_worker(void *arg); typedef struct iotd_ctx_s { iotd_conf_t conf; } iotd_ctx_t; void banner(const char *program) { printf("Copyright (C) 2018 LingYun IoT Studio.\n"); printf("%s Version 1.0.0 Build on @ %s %s\n", program, __DATE__, __TIME__); } static void program_usage(const char *progname) { banner(progname); printf("Usage: %s [OPTION]...\n", progname); printf(" %s is a daemon program running on the device, which used to \n", progname); printf("receive date from serial and transfer the data to remote server by socket\n"); printf("\nMandatory arguments to long options are mandatory for short options too:\n"); printf(" -d[debug ] Running in debug mode\n"); printf(" -l[level ] Set the log level as [0..%d]\n", LOG_LEVEL_MAX-1); printf(" -h[help ] Display this help information\n"); printf(" -v[version ] Display the program version\n"); return; } int main(int argc, char **argv) { int opt; int i = 0; int rv = 0; int debug = 0; const char *progname=NULL; char pid_file[64] = { 0 }; /* The file used to record the PID */ char *conf_file = "etc/iotd.conf"; char *log_file = DEF_LOG_FILE; int log_level = DEF_LOG_LEVEL; iotd_ctx_t iotd_ctx; // pthread_t tid; iotd_conf_t *conf; logger_t *logger; memset(&iotd_ctx, 0, sizeof(iotd_ctx)); conf = &iotd_ctx.conf; logger = &conf->logger; struct option long_options[] = { {"conf", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, {"level", required_argument, NULL, 'l'}, {"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; progname = basename(argv[0]); /* Parser the command line parameters */ while ((opt = getopt_long(argc, argv, "c:dl:vh", long_options, NULL)) != -1) { switch (opt) { case 'c': /* Set configure file */ conf_file = optarg; break; case 'd': /* Set debug running */ debug = 1; log_file = DBG_LOG_FILE; break; case 'l': /* Set the log level */ i = atoi(optarg); log_level = i>LOG_LEVEL_MAX ? LOG_LEVEL_MAX-1 : i; logger->flag |= CP_LOGGER_LEVEL_OPT; break; case 'v': /* Get software version */ banner(progname); /* Defined in version.h */ return EXIT_SUCCESS; case 'h': /* Get help information */ program_usage(progname); return 0; default: break; } /* end of "switch(opt)" */ } snprintf(pid_file, sizeof(pid_file), "/var/run/%s.pid", progname); if( !debug ) { if( check_daemon_running(pid_file) ) { printf("Programe already running, exit now.\n"); return -1; } } if ( !cp_log_init(logger, log_file, log_level, 1024/*KB*/) || cp_log_open() ) { printf("Logger initialize failure with file: %s\n", logger->file); return -1; } log_nrml("Init default logger file \"%s\" ok\n", log_file); /* Parser configure file and start the initialize log */ rv = parser_iotd_conf(conf_file, conf); if(rv < 0) { log_fatal("Parse configure file %s failure, rv=%d\n", conf_file, rv); goto CleanUp; } /* If configure file logger is not same as default one, then reopen the logger system */ if( !debug && strncmp(logger->file, DEF_LOG_FILE, strlen(DEF_LOG_FILE)) ) { log_warn("Reinitiase logger to [%s]\n", logger->file); cp_log_close(); if( cp_log_open() ) { printf("Logger reopen failure with file: %s\n", logger->file); return -1; } } if( !debug ) { if( set_daemon_running(pid_file) ) { log_fatal("Set program \"%s\" running as daemon failure.\n", progname); goto CleanUp; } } cp_install_proc_signal(); /* start watchdog thread worker */ //thread_start(&tid, watchdog_worker, NULL); /* Start MQTT thread worker */ if( conf->mqtt_conf.enable ) { log_nrml("start MQTT publish process thread\n"); //thread_start(&tid, mqtt_worker, (void *)&iotd_ctx ); } /* Start NB-IoT thread worker */ if( conf->nbiot_conf.enable ) { log_nrml("start NB-IoT process thread\n"); //thread_start(&tid, nbiot_worker, (void *)&iotd_ctx ); } /* Start LoRa thread worker */ if( conf->nbiot_conf.enable ) { log_nrml("start LoRa AP process thread\n"); //thread_start(&tid, nbiot_worker, (void *)&iotd_ctx ); } while( !g_cp_signal.stop ) { sleep(1); } CleanUp: log_warn("Terminate main program \"%s\".\n", progname); unlink(pid_file); cp_log_term(); return rv; } #define WTD_DEV "/dev/watchdog" void *watchdog_worker(void *arg) { int wtd_fd = -1; int timeout = 120; /* 2 minutes */ int times = 0; log_nrml("start watchdog thread\n"); if( (wtd_fd=open(WTD_DEV, O_RDWR)) < 0 ) { log_err("Open watchdog '%s' failure: %s\n", WTD_DEV, strerror(errno)); return NULL; } ioctl(wtd_fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD); ioctl(wtd_fd, WDIOC_SETTIMEOUT, &timeout); log_nrml("Start watchdog on timeout %d seconds\n", timeout); while( !g_cp_signal.stop ) { if( times++ > 20 ) { log_dbg("start feed watchdog now\n"); ioctl(wtd_fd, WDIOC_KEEPALIVE, NULL); times = 0; } sleep(1); } close(wtd_fd); log_warn("watchdog thread worker exit\n"); return NULL; }