LingYun IoT Studio NB-IoT research project
Guo Wenxue
2018-11-20 67f8a597480e9951ea40e84997011660d09eeb84
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*********************************************************************************       
 * 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;
}