APUE Learning Example Source Code
guowenxue
2023-11-06 d81310d55b9b7d07904c19f879f50e52fd7be489
prj1_tlv/tlv_client.c
@@ -19,10 +19,21 @@
#include "logger.h"
#include "proc.h"
#include "ds18b20.h"
#include "socket.h"
#include "tlv_pack.h"
#include "sqlite_cli.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)
{
@@ -38,6 +49,7 @@
    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"); 
@@ -52,17 +64,27 @@
    int                   opt; 
    int                   i = 0; 
    //int                   rv = 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'}, 
@@ -70,15 +92,19 @@
        {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, "c:dl:vh", long_options, NULL)) != -1)
    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;
@@ -105,8 +131,14 @@
        } 
    }
    if( !host )
    {
        printf("ERROR: No argument specify host server address and port, please refer to usage\n");
        return 1;
    }
    /* check program already running or not, if already running then exit, or set running as daemon */
    snprintf(pid_file, sizeof(pid_file), "/var/run/%s.pid", progname);
    snprintf(pid_file, sizeof(pid_file), "/tmp/%s.pid", progname);
    if( !debug )
    {
        if( check_daemon_running(pid_file) )
@@ -114,29 +146,194 @@
            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 -1;
        return 2;
    }
    log_nrml("Program start running\n");
    /* install signal proc handler */
    install_proc_signal();
    log_nrml("Program start running\n");
    if( clidb_init("./tlv_client.db")< 0)
    {
        log_err("initial sqlite database failure\n");
        return 3;
    }
    last_time = 0;
    /* g_signal.stop defined in proc.c, and will be set when catch stop signal */
    while( !g_signal.stop )
    {
        log_dbg("Program still running\n");
        sleep(3);
        time(&cur_time);
        if( cur_time-last_time > 10)
        {
            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( SOCK_STAT_CONNECTED == sock.status )
        {
            /* send current new sample TLV packet  */
            if( tlv.flag&TLV_FLAG_TX )
            {
                if(0 == socket_send_tlv_pack(&sock, &tlv, DEF_ACK_TIMEOUT, DEF_RETRYTIMES) )
                {
                    tlv.flag = 0;
                }
            }
            /* get TLV apcket from database and send it by socket, maxim 5 records  */
            for(i=0; i<5; i++)
            {
                int            id;
                tlv_buf_t      tmp;
                if( clidb_pop_tlvpack(&tmp, &id) <= 0 )
                {
                    break;
                }
                /* send the TLV packet from database */
                if(0 == socket_send_tlv_pack(&sock, &tmp, DEF_ACK_TIMEOUT, DEF_RETRYTIMES) )
                {
                    /* delete the record from DB */
                    clidb_del_tlvpack(id);
                }
            }
        }
        if( tlv.flag & TLV_FLAG_DB )
        {
            clidb_push_tlvpack(&tlv);
            tlv.flag = 0;
        }
        sleep(1);
    }
    logger_term();
    clidb_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];
    if( sock->status != SOCK_STAT_CONNECTED )
        return -1;
    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 0;
        }
        /* todo: parser ACK from buf  */
        if( ACK )
            break;
    }
    return 0;
}