
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
// for basename
#include <libgen.h>
// serial IO, termios
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "cwglib.h"
#include "iowfile.h"
#include "iowserial.h"
// Z85 decode
#include "z85.h"
// record structure defs
#include "licor8xx-shared.h"

#define CWG_BUFLEN_BYTES 4096
#define CWG_CMD_SAMPLE_BYTES 64

/// @fn void s_termination_handler (int signum)
/// @brief termination signal handler.
/// @param[in] signum signal number
/// @return none
static void s_termination_handler (int signum)
{
    switch (signum) {
#if ! defined(__WIN32) && ! defined(__WIN64)
        case SIGHUP:
#endif
        case SIGINT:
        case SIGTERM:
            fprintf(stderr,"\nsig received[%d]\n",signum);
            wser_signal_int(true);
            break;
        default:
            fprintf(stderr,"\ns_termination_handler: sig not handled[%d]\n",signum);
            break;
    }
}
// End function termination_handler

int cwg_test(char *ser_dev)
{
    int retval=-1;
    wser_t *port = NULL;

    printf("CMD_CRON_SUSPEND[%s]\r\n",CMD_CRON_SUSPEND(1000));
    printf("CMD_LAST_SAMPLE[%s]\r\n",CMD_LAST_SAMPLE(b));
    printf("CMD_LAST_NSAMPLE[%s]\r\n",CMD_LAST_NSAMPLE(10,c));
    printf("CMD_LAST_SCSAMPLE[%s]\r\n",CMD_LAST_SCSAMPLE(0,2,b));
    printf("CMD_UPLOAD_TO_SEC[%d]\r\n",CMD_UPLOAD_TO_SEC(1024));
    printf("CMD_LAST_NTO_SEC[%d]\r\n",CMD_LAST_NTO_SEC(3));
    printf("CMD_MKCMD[%s]\r\n",CMD_MKCMD("%s cwglib.scr",CMD_UPLOAD_Q));

    if(NULL!=ser_dev && (port=wser_new(ser_dev))!=NULL ){
        wser_show(port,true,5);
        if(wser_connect(port,BPS_9600,CSZ_8,PAR_N,CSB_1,FLOW_N)==0){

            char iobuf[CWG_BUFLEN_BYTES]={0};

            // disable prompt and echo
            wser_set_wt(port,3);
            wser_write_read_ln(port, CMD_HOST_PROMPT_DIS, strlen(CMD_HOST_PROMPT_DIS), iobuf, CWG_BUFLEN_BYTES, CRLF, 1);
            wser_write_read_ln(port, CMD_HOST_ECHO_DIS, strlen(CMD_HOST_PROMPT_DIS), iobuf, CWG_BUFLEN_BYTES, CRLF, 1);

            // suspend cron
            wser_write_read_ln(port, CMD_CRON_DISABLE, strlen(CMD_CRON_DISABLE), iobuf, CWG_BUFLEN_BYTES, CRLF, 1);

            // verify cron suspended
            wser_write_read_ln(port, CMD_CRON_NEXT, strlen(CMD_CRON_NEXT), iobuf, CWG_BUFLEN_BYTES, CRLF, 2);

            char act=0;
            float cron_next=0;
            if(sscanf(iobuf,"%f %c",&cron_next,&act)==2 && act=='-' ){
                OUT_ERR("cron disabled nxt[%.2f] act[%c]%s",cron_next,act,LINEEND);
            }

            // enable prompt
            wser_write_read_ln(port, CMD_HOST_PROMPT_EN, strlen(CMD_HOST_PROMPT_EN), iobuf, CWG_BUFLEN_BYTES, CWG_PROMPT, 1);

            // issue println (demo: read until prompt)
            wser_write_read_ln(port, CMD_MKCMD("%s 'OK'",CMD_PRINTLN), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, CWG_PROMPT, 1);

            // request latest sample (various formats)

            // build command: last sample (csv)...
            memset(iobuf,0,CWG_BUFLEN_BYTES);
            wser_write_read_ln(port, CMD_MKCMD("%s",CMD_LAST_SAMPLE(c)), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, CRLF, CMD_LAST_NTO_SEC(4));
            licor_zrecord_t *zrec=licor_parse_csv(NULL, 0, iobuf);
            if(NULL!=zrec){
                licor_zrecord_show(zrec, true, 5);
                free(zrec);
                zrec=NULL;
            }else{TRACE();}

            // build command: samples 0:1 (Z85)...
            memset(iobuf,0,CWG_BUFLEN_BYTES);
            char *foo =CMD_MKCMD("%s",CMD_LAST_SCSAMPLE(0,2,b));
            OUT_ERR("CMD_LAST_SCSAMPLE[%s] len[%"FMT_SZ"]\r\n",foo,CMD_LEN);
            wser_write_read_ln(port, foo, CMD_LEN, iobuf, CWG_BUFLEN_BYTES, NULL, CMD_LAST_NTO_SEC(4));

            // iterate over samples, convert and show
            memset(iobuf,0,CWG_BUFLEN_BYTES);
            char *cur[2]={iobuf,strstr(iobuf,CRLF)};
            while(NULL!=cur[1]){
                cur[1]+=2;
                OUT_ERR("b85 cur[%p/%p] len[%ld]\r\n",cur[0],cur[1],(long int)(cur[1]-cur[0]));

                zrec = (licor_zrecord_t *)Z85_decode(NULL,0,cur[0],(cur[1]-cur[0]));
                if(NULL!=zrec){
                    licor_zrecord_show(zrec, true, 5);
                    free(zrec);
                    zrec=NULL;
                }
                cur[0]=cur[1];
                cur[1]=strstr(cur[0],CRLF);
            }
            // upload a script

            // disable echo and prompt
            wser_write_read_ln(port, CMD_HOST_PROMPT_DIS, strlen(CMD_HOST_PROMPT_DIS), iobuf, CWG_BUFLEN_BYTES, CRLF, 1);
            wser_write_read_ln(port, CMD_HOST_ECHO_DIS, strlen(CMD_HOST_PROMPT_DIS), iobuf, CWG_BUFLEN_BYTES, CRLF, 1);

            // initiate upload
            memset(iobuf,0,CWG_BUFLEN_BYTES);
            wser_write_read_ln(port, CMD_MKCMD("%s cwglib.scr",CMD_UPLOAD_Q), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, NULL,1);

            // write script
            char scr_buf[]={
                "get time\r\n"\
                "PRINTLN \"hello cwglib\"\r\n"\
                "END\r\n\x04"
            };

            char binfile[2048]={0};
            int i=0;
            while(i<2048){
                binfile[i]=(i%128);
                i++;
            }
            memset(iobuf,0,CWG_BUFLEN_BYTES);
            foo =CMD_MKCMD("%s q b:2048 T2 cwgbin.dat",CMD_UPLOAD);
            OUT_ERR("CMD_UPLOAD[%s] len[%"FMT_SZ"]\r\n",foo,CMD_LEN);

            wser_write_read_ln(port, scr_buf, strlen(scr_buf), iobuf, CWG_BUFLEN_BYTES, CWG_PROMPT, CMD_UPLOAD_TO_SEC(strlen(scr_buf)));

            wser_write_read_ln(port, foo, CMD_LEN, iobuf, CWG_BUFLEN_BYTES, NULL,1);
            wser_set_wt(port, 2);
            wser_write(port,binfile,2048,NULL);
            wser_read_until(port, "BIN_EOT\r\n", iobuf, CWG_BUFLEN_BYTES, 2+((2*2048)/1000));

            wser_write_read_ln(port, CMD_MKCMD("%s rb: cwgbin.dat",CMD_CAT), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, NULL,10);

            memset(iobuf,0,CWG_BUFLEN_BYTES);
            int32_t rb=0;
            while( (rb=wser_read_until(port, CRLF, iobuf, CWG_BUFLEN_BYTES, 1))>0){
                OUT_ERR("RS[");
                int i=0;
                while(rb>0 && i<rb){
                    OUT_ERR((isprint((int)iobuf[i]) ? "%c":"<%02X>"),(byte)iobuf[i]);
                    i++;
                }
                OUT_ERR("]/%"FMT_D32"%s",rb,LINEEND);
                memset(iobuf,0,CWG_BUFLEN_BYTES);
            }

            // rm bin file
//            cwg_write_read_cmd(port, CMD_MKCMD("%s cwgbin.dat",CMD_RM), iobuf, CWG_BUFLEN_BYTES, CRLF, 1);

            // dump binary file
//            cwg_write_read_cmd(port, CMD_MKCMD("%s dat1111.000 out:r",CMD_LCAT) , iobuf, CWG_BUFLEN_BYTES, "end of file",10);
//            cwg_drain_rx_base(port,-1,10,1);


            // load script
            wser_write_read_ln(port, CMD_MKCMD("%s cwglib.scr",CMD_SCR_LOAD), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, CRLF, 1);
            // run script
            wser_write_read_ln(port, CMD_MKCMD("%s out:h cwglib.scr",CMD_SCR_RUN), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, CRLF, 1);

            // get additional script output lines
            memset(iobuf,0,CWG_BUFLEN_BYTES);
            rb=0;
            while( (rb=wser_read_until(port, CRLF, iobuf, CWG_BUFLEN_BYTES, 1))>0){
                OUT_ERR("RS[");
                int i=0;
                while(rb>0 && i<rb){
                    OUT_ERR((isprint((int)iobuf[i]) ? "%c":"<%02X>"),(byte)iobuf[i]);
                    i++;
                }
                OUT_ERR("]/%"FMT_D32"%s",rb,LINEEND);
                memset(iobuf,0,CWG_BUFLEN_BYTES);
            }
            // unload script
            wser_write_read_ln(port, CMD_MKCMD("%s cwglib.scr",CMD_SCR_UNLOAD), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, CRLF, 1);
            // rm script
            wser_write_read_ln(port, CMD_MKCMD("%s cwglib.scr",CMD_RM), CMD_LEN, iobuf, CWG_BUFLEN_BYTES, CRLF, 1);

//            cwg_upload_file(port,"cwgup.dat","foo.out",true);
//            cwg_download_file(port,"cwgdl.dat","cwgup.dat",true);
            cwg_fget_lastn(port, "cwgfgetln.dat", (IOW_CREATE_ALWAYS|IOW_WRITE|IOW_READ), "DAT2011.000", 5, "r");

            byte zmem[5*LI_ZREC_SIZEN(6)]={0};
            cwg_mget_lastn(port, zmem, (5*LI_ZREC_SIZEN(6)), "DAT2011.000", 5, "r");

            licor_zrecord_t *pzrec = (licor_zrecord_t *)zmem;
            licor_zrecord_show(pzrec,true,5);

            cwg_fget_n(port, "cwgfgetn.dat", (IOW_CREATE_ALWAYS|IOW_WRITE|IOW_READ), "DAT2011.000",8,3, "r");
            memset(zmem,0,5*LI_ZREC_SIZEN(6));
            cwg_mget_n(port, zmem, (5*LI_ZREC_SIZEN(6)), "DAT2011.000", 8, 3, "r");
            licor_zrecord_show(pzrec,true,5);


            cwg_fcget_lastn(port, "cwgfcgetln.dat", (IOW_CREATE_ALWAYS|IOW_WRITE|IOW_READ), "SYS2102.000", 5);
            byte cmem[5*500]={0};
            cwg_mcget_lastn(port, cmem, (5*500), "SYS2102.000", 5);
            fprintf(stderr,"%s\r\n",cmem);


        }else{
            OUT_ERR("connect error\r\n");
        }
        wser_destroy(&port);
    }
    return retval;
}

int main(int argc, char **argv)
{
    int retval=-1;

#if defined(__WIN32) || defined(__WIN64)
    signal(SIGINT,s_termination_handler);
#else
    // configure signal handling
    // for main thread
    struct sigaction saStruct;

    sigemptyset(&saStruct.sa_mask);
    saStruct.sa_flags = 0;
    saStruct.sa_handler = s_termination_handler;
    sigaction(SIGINT, &saStruct, NULL);
#endif

    char *device=NULL;
    if(argc>1){
        device=argv[1];
    }else{
        OUT_ERR("use %s <device>\n",basename(argv[0]));
    }

    OUT_CONS("device[%s]\r\n",(device!=NULL?device:"NULL"));

    if(cwg_test(device)==ERR_SUCCESS){
        retval=0;
    }


    return retval;
}

