/*********************************************************************************
|
* Copyright: (C) 2019 LingYun IoT System Studio
|
* All rights reserved.
|
*
|
* Filename: socket_client.c
|
* Description: This is a socket client program to report RPi's temperature
|
*
|
* Version: 1.0.0(29/01/19)
|
* Author: Guo Wenxue <guowenxue@gmail.com>
|
* ChangeLog: 1, Release initial version on "29/01/19 15:34:41"
|
*
|
********************************************************************************/
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <unistd.h>
|
#include <time.h>
|
#include <getopt.h>
|
#include <libgen.h>
|
#include <string.h>
|
#include <errno.h>
|
|
#include "logger.h"
|
#include "ds18b20.h"
|
#include "proc.h"
|
#include "packet.h"
|
#include "socket.h"
|
#include "database.h"
|
|
#define PROG_VERSION "v1.0.0"
|
#define DAEMON_PIDFILE "/tmp/socketc.pid"
|
|
static void print_usage(char *progname)
|
{
|
printf("Usage: %s [OPTION]...\n", progname);
|
printf(" %s is LingYun studio temperature socket client program running on RaspberryPi\n", progname);
|
|
printf("\nMandatory arguments to long options are mandatory for short options too:\n");
|
printf("-i(ipaddr) : sepcify server IP address\n");
|
printf("-p(--port) : sepcify server port.\n");
|
printf("-I(--interval): sepcify report time interval, default 60 seconds\n");
|
printf("-d(--debug) : running in debug mode\n");
|
printf("-h(--help) : display this help information\n");
|
printf("-v(--version) : display the program version\n");
|
|
printf("\n%s version %s build on %s %s\n", progname, PROG_VERSION, __DATE__, __TIME__);
|
return;
|
}
|
|
int main (int argc, char **argv)
|
{
|
char *progname=NULL;
|
int daemon = 1;
|
int rv;
|
int rowid = 0;
|
time_t now;
|
|
char *logfile="/tmp/socketc.log";
|
int loglevel=LOG_LEVEL_INFO;
|
int logsize=10; /* logfile size max to 10K */
|
|
socket_t sock;
|
char *serverip = NULL;
|
int port = 0;
|
int interval = 60; /* default report termperature every 60 seconds */
|
|
time_t last_time = 0;
|
int sample_flag = 0;
|
|
char pack_buf[1024];
|
int pack_bytes = 0;
|
pack_info_t pack_info;
|
//pack_proc_t pack_proc = packet_segmented_pack; /* use segmented string packet */
|
//pack_proc_t pack_proc = packet_json_pack; /* use JSON string packet */
|
pack_proc_t pack_proc = packet_tlv_pack; /* use TLV(Tag Length Value) packet */
|
|
struct option opts[] = {
|
{"ipaddr", required_argument, NULL, 'i'},
|
{"port", required_argument, NULL, 'p'},
|
{"interval", required_argument, NULL, 'I'},
|
{"debug", no_argument, NULL, 'd'},
|
{"version", no_argument, NULL, 'v'},
|
{"help", no_argument, NULL, 'h'},
|
{NULL, 0, NULL, 0}
|
};
|
|
progname = (char *)basename(argv[0]);
|
|
/* Parser the command line parameters */
|
while( (rv=getopt_long(argc, argv, "i:p:I:dvh", opts, NULL)) != -1 )
|
{
|
switch (rv)
|
{
|
case 'i': /* set socket server hostname or IP address */
|
serverip=optarg;
|
break;
|
|
case 'p': /* set socket server listen port */
|
port=atoi(optarg);
|
break;
|
|
case 'I': /* set report time interval */
|
interval=atoi(optarg);
|
break;
|
|
case 'd': /* set debug running */
|
daemon = 0;
|
logfile="console";
|
loglevel=LOG_LEVEL_DEBUG;
|
break;
|
|
case 'v': /* get software version */
|
printf("%s version %s\n", progname, PROG_VERSION);
|
return 0;
|
|
case 'h': /* get help information */
|
print_usage(progname);
|
return 0;
|
|
default:
|
break;
|
}
|
}
|
|
if( !serverip || !port )
|
{
|
print_usage(argv[0]);
|
return 0;
|
}
|
|
/* initial socket context */
|
socket_init(&sock, serverip, port);
|
|
/* open logger system */
|
if( log_open(logfile, loglevel, logsize, THREAD_LOCK_NONE) < 0 )
|
{
|
fprintf(stderr, "Initial logger failed\n");
|
return 1;
|
}
|
|
/* open database for cache data */
|
if( db_open("sock_client.db") < 0 )
|
{
|
fprintf(stderr, "Initial database failed\n");
|
rv = 2;
|
goto cleanup;
|
}
|
|
/* check whether the program is running; if not, start it in the background. */
|
if( check_set_program_running(daemon, DAEMON_PIDFILE) < 0 )
|
{
|
fprintf(stderr, "Program is already running. Exiting.\n");
|
rv = 3;
|
goto cleanup;
|
}
|
|
/* install signal handler */
|
install_default_signal();
|
|
log_info("socket client start running.\n");
|
|
while( ! g_signal.stop )
|
{
|
/* +----------------------------------+
|
* | check and sample temperature |
|
* +----------------------------------+*/
|
|
sample_flag = 0; /* clear sample flag */
|
time(&now); /* get current time */
|
|
if( difftime(now, last_time) >= interval )
|
{
|
if( (rv=ds18b20_get_temperature(&pack_info.temper)) < 0 )
|
{
|
log_error("DS18B20 sample temperature failure, rv=%d\n", rv);
|
continue;
|
}
|
log_info("DS18B20 sample termperature %.2f oC\n", pack_info.temper);
|
|
get_devid(pack_info.devid, sizeof(pack_info.devid), 88);
|
get_time(&pack_info.sample_time);
|
|
pack_bytes = pack_proc(&pack_info, (uint8_t *)pack_buf, sizeof(pack_buf));
|
log_dump(LOG_LEVEL_DEBUG, NULL, pack_buf, pack_bytes);
|
|
last_time = now; /* update last sample time */
|
sample_flag = 1; /* set sample flag */
|
}
|
|
/* +---------------------------------+
|
* | check and do socket connect |
|
* +---------------------------------+*/
|
|
/* start connect to server if not connected */
|
if( !socket_check(&sock) )
|
{
|
socket_connect(&sock);
|
}
|
|
/* +-------------------------------+
|
* | socket disconnect |
|
* +-------------------------------+*/
|
if( !sock.connected )
|
{
|
if( sample_flag )
|
{
|
db_write(pack_buf, pack_bytes);
|
}
|
|
/* Bypass the data send procedure for socket disconnect */
|
continue;
|
}
|
|
/* +-------------------------------+
|
* | socket connected |
|
* +-------------------------------+*/
|
|
/* socket send sample packet */
|
if( sample_flag )
|
{
|
log_debug("socket send sample packet bytes[%d]: %s\n", pack_bytes, pack_buf);
|
if( socket_send(&sock, pack_buf, pack_bytes) < 0 )
|
{
|
log_warn("socket send sample packet failure, save it in database now.\n");
|
db_write(pack_buf, pack_bytes);
|
continue;
|
}
|
}
|
|
/* socket send cache packet */
|
if( !db_read(pack_buf, sizeof(pack_buf), &pack_bytes, &rowid) )
|
{
|
log_debug("socket send database packet bytes[%d]: %s\n", pack_bytes, pack_buf);
|
if( socket_send(&sock, pack_buf, pack_bytes) < 0 )
|
{
|
log_error("socket send database packet failure");
|
continue;
|
}
|
else
|
{
|
log_warn("socket send database packet okay, remove it from database now.\n");
|
db_remove(rowid);
|
}
|
}
|
|
msleep(5);
|
}
|
|
rv = 0;
|
|
cleanup:
|
socket_term(&sock);
|
db_close();
|
log_close();
|
unlink(DAEMON_PIDFILE);
|
|
return rv;
|
}
|