/*********************************************************************************
|
* Copyright: (C) 2020 LingYun IoT System Studio
|
* All rights reserved.
|
*
|
* Filename: tlv_client.c
|
* Description: This is a socket client program used to report RPi's temperature
|
* to socket server by TLV protocal.
|
*
|
* Version: 1.0.0(2020年04月14日)
|
* Author: Guo Wenxue <guowenxue@gmail.com>
|
* ChangeLog: 1, Release initial version on "2020年04月14日 00时52分56秒"
|
*
|
********************************************************************************/
|
#include <stdio.h>
|
#include <unistd.h>
|
#include <string.h>
|
#include <getopt.h>
|
#include <libgen.h>
|
|
#include "logger.h"
|
#include "proc.h"
|
#include "ds18b20.h"
|
#include "socket.h"
|
#include "tlv_pack.h"
|
|
#define PROG_VERSION "1.0.0"
|
#define RPI_SN "RPI00001"
|
|
#define DEF_LOG_FILE "tlv_client.log"
|
|
#define DEF_ACK_TIMEOUT 2 /* wait for ACK timeout value */
|
#define DEF_RETRYTIMES 3 /* receive ACK timeout or get NAK, retry to send times */
|
int socket_send_tlv_pack(socket_t *sock, tlv_buf_t *tlv, int timeout, int retry_times);
|
|
int packtlv_msg(tlv_buf_t *tlv, char *sn, uint16_t temp, struct tm *tm);
|
|
static void banner(void)
|
{
|
printf("Version %s build on %s %s\n", PROG_VERSION, __DATE__, __TIME__);
|
printf("Copyright (C) 2020 LingYun IoT System Studio.\n\n");
|
|
return ;
|
}
|
|
static void program_usage(const char *progname)
|
{
|
printf("Usage: %s [OPTION]...\n", progname);
|
printf("This program used to connect to server and send RPi's temperature by TLV protocal.\n");
|
|
printf("\nMandatory arguments to long options are mandatory for short options too:\n");
|
printf(" -H[Host ] Specify host server address and port, foramt as \"127.0.0.1:9000\"\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");
|
printf("\n");
|
|
banner();
|
return ;
|
}
|
|
int main (int argc, char *argv[])
|
{
|
int opt;
|
int i = 0;
|
int rv = 0;
|
int debug = 0;
|
|
char pid_file[64] = { 0 }; /* The file used to record the PID */
|
const char *progname=NULL;
|
|
char *host = "127.0.0.1:10086";
|
//char *host = "baidu.com:10086";
|
int log_level = LOG_LEVEL_NRML;
|
char *log_file = DEF_LOG_FILE;
|
|
logger_t logger;
|
socket_t sock;
|
tlv_buf_t tlv;
|
|
uint16_t temp;
|
struct tm *tm;
|
time_t cur_time, last_time = 0;
|
|
struct option long_options[] = {
|
{"Host", required_argument, NULL, 'H'},
|
{"debug", no_argument, NULL, 'd'},
|
{"level", required_argument, NULL, 'l'},
|
{"version", no_argument, NULL, 'v'},
|
{"help", no_argument, NULL, 'h'},
|
{NULL, 0, NULL, 0}
|
};
|
|
memset(&sock, 0, sizeof(sock));
|
memset(&logger, 0, sizeof(logger));
|
|
progname = basename(argv[0]); /* get program name */
|
|
/* parser the command line parameters */
|
while ((opt = getopt_long(argc, argv, "H:dl:vh", long_options, NULL)) != -1)
|
{
|
switch (opt)
|
{
|
case 'H':
|
host=optarg;
|
break;
|
|
case 'd': /* set debug running */
|
debug = 1;
|
log_level= LOG_LEVEL_DEBUG;
|
log_file = NULL; /* use standard output */
|
break;
|
|
case 'l': /* set the log level */
|
i = atoi(optarg);
|
log_level = i>LOG_LEVEL_MAX ? LOG_LEVEL_MAX-1 : i;
|
logger.flag |= FLAG_LOGGER_LEVEL_OPT;
|
break;
|
|
case 'v': /* print software version */
|
banner();
|
return EXIT_SUCCESS;
|
|
case 'h': /* print help information */
|
program_usage(progname);
|
return 0;
|
|
default:
|
break;
|
}
|
}
|
|
#if 1
|
if( !host )
|
{
|
printf("ERROR: No argument specify host server address and port, please refer to usage\n");
|
// return 1;
|
}
|
|
|
#endif
|
|
/* check program already running or not, if already running then exit, or set running as daemon */
|
snprintf(pid_file, sizeof(pid_file), "/tmp/%s.pid", progname);
|
if( !debug )
|
{
|
if( check_daemon_running(pid_file) )
|
{
|
printf("Programe already running, exit now.\n");
|
return -1;
|
}
|
|
set_daemon_running(pid_file);
|
}
|
|
record_daemon_pid(pid_file);
|
|
/* initial and open logger system */
|
if( logger_init(&logger, log_file, log_level, 512)<0 || logger_open()<0 )
|
{
|
printf("ERROR: Initialise logger system failure\n");
|
return 2;
|
}
|
|
/* install signal proc handler */
|
install_proc_signal();
|
|
log_nrml("Program start running\n");
|
|
#if 0
|
if( initial_db(&sqldb, db_file) < 0)
|
{
|
log_err("initialise sqlite database failure\n");
|
return 3;
|
}
|
#endif
|
|
last_time = 0;
|
|
/* g_signal.stop defined in proc.c, and will be set when catch stop signal */
|
while( !g_signal.stop )
|
{
|
time(&cur_time);
|
if( cur_time-last_time > 3)
|
{
|
log_nrml("start sample temperature now.\n");
|
rv = 0;
|
temp = 0x1122;
|
//rv = ds18b20_get_temperature(&temp);
|
if( 0 == rv )
|
{
|
/* convert time_t to tm format */
|
tm=localtime(&cur_time);
|
last_time = cur_time;
|
|
packtlv_msg(&tlv, RPI_SN, temp, tm);
|
logger_dump(LOG_LEVEL_DEBUG, tlv.buf, tlv.len);
|
|
/* this message need to be transmit and saved in database if send failure */
|
tlv.flag = TLV_FLAG_TX | TLV_FLAG_DB;
|
}
|
else
|
{
|
log_err("DS18B20 get temperature failure\n");
|
}
|
}
|
|
if( SOCK_STAT_CONNECTED != sock.status )
|
{
|
if( socket_connect(&sock, -1, host, MODE_NONBLOCK) < 0)
|
{
|
log_err("connect to server [%s:%d] failure\n", sock.raddr, sock.rport);
|
}
|
}
|
|
if( (tlv.flag&TLV_FLAG_TX) && SOCK_STAT_CONNECTED==sock.status )
|
{
|
if(0 == socket_send_tlv_pack(&sock, &tlv, DEF_ACK_TIMEOUT, DEF_RETRYTIMES) )
|
{
|
tlv.flag = 0;
|
}
|
}
|
|
#if 0
|
/* need to send TLV packet in database now */
|
for(i=0; i<5; i++)
|
{
|
/* get a TLV record from DB and send it by socket */
|
/* rv<0: Erorr rv=0: No record >0: record count */
|
rv = get_db_tlv_pack(sqldb, tlv, size) ;
|
if( rv <= 0)
|
break;
|
|
if( 0 == socket_send_tlv_pack() )
|
{
|
/* delete the record from DB */
|
del_db_tlv_pack();
|
}
|
}
|
|
SAVE_DB:
|
if( tlv_buf.flag & TLV_FLAG_DB)
|
{
|
record_db_tlv(sqldb, tlv_buf, tlv_len);
|
}
|
#endif
|
|
sleep(1);
|
}
|
|
logger_term();
|
|
//db_term();
|
|
return 0;
|
}
|
|
/* Packet 3 TLV message together: with SN, temperature, date&time */
|
int packtlv_msg(tlv_buf_t *tlv, char *sn, uint16_t temp, struct tm *tm)
|
{
|
int rv;
|
|
if( !tlv )
|
{
|
log_err("Invalid input arguments\n");
|
return -1;
|
}
|
|
memset(tlv->buf, 0, sizeof(tlv->buf)); /* clear data in buffer */
|
tlv->size = sizeof(tlv->buf); /* buffer free space size */
|
tlv->len = 0; /* buffer data length */
|
|
if( sn )
|
{
|
rv = packtlv_sn(&tlv->buf[tlv->len], tlv->size, sn);
|
if( rv > 0 )
|
{
|
tlv->len += rv;
|
tlv->size -= rv;
|
}
|
}
|
|
if( temp )
|
{
|
rv = packtlv_temp(&tlv->buf[tlv->len], tlv->size, temp);
|
if( rv > 0 )
|
{
|
tlv->len += rv;
|
tlv->size -= rv;
|
}
|
}
|
|
if( tm )
|
{
|
rv = packtlv_time(&tlv->buf[tlv->len], tlv->size, tm);
|
if( rv > 0 )
|
{
|
tlv->len += rv;
|
tlv->size -= rv;
|
}
|
}
|
|
return 0;
|
}
|
|
int socket_send_tlv_pack(socket_t *sock, tlv_buf_t *tlv, int timeout, int retry_times)
|
{
|
int i;
|
int rv = 0;
|
char buf[128];
|
|
log_info("start to send tlv packet from socket now\n");
|
|
for(i=0; i<retry_times; i++)
|
{
|
if( (rv=socket_send(sock, tlv->buf, tlv->len)) < 0 )
|
{
|
log_err("send tlv packet failure, rv=%d\n", rv);
|
return -1;
|
}
|
|
if( (rv=socket_recv(sock, buf, sizeof(buf), timeout)) < 0 )
|
{
|
log_err("read ACK from server failure, rv=%d\n", rv);
|
return -2;
|
}
|
}
|
|
return 0;
|
}
|