/*********************************************************************************
|
* 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 <guowenxue@aliyun.com>
|
* ChangeLog: 1, Release initial version on "2018/11/19 22:05:56 CST"
|
*
|
********************************************************************************/
|
#include <stdio.h>
|
#include <getopt.h>
|
#include <sys/types.h>
|
#include <sys/wait.h>
|
#include <signal.h>
|
#include <linux/input.h>
|
#include <linux/kd.h>
|
#include <linux/keyboard.h>
|
#include <linux/watchdog.h>
|
#include <libgen.h>
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
#include <fcntl.h>
|
|
#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;
|
}
|