///
/// @file cwglib.c
/// @authors k. Headley
/// @date 05 dec 2019

/// Carbon Wave Glider client library implementation

/// @sa doxygen-examples.c for more examples of Doxygen markup


/////////////////////////
// Terms of use
/////////////////////////
/*
 Copyright Information
 
 Copyright 2002-2019 MBARI
 Monterey Bay Aquarium Research Institute, all rights reserved.
 
 Terms of Use
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version. You can access the GPLv3 license at
 http://www.gnu.org/licenses/gpl-3.0.html
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details
 (http://www.gnu.org/licenses/gpl-3.0.html)
 
 MBARI provides the documentation and software code "as is", with no warranty,
 express or implied, as to the software, title, non-infringement of third party
 rights, merchantability, or fitness for any particular purpose, the accuracy of
 the code, or the performance or results which you may obtain from its use. You
 assume the entire risk associated with use of the code, and you agree to be
 responsible for the entire cost of repair or servicing of the program with
 which you are using the code.
 
 In no event shall MBARI be liable for any damages, whether general, special,
 incidental or consequential damages, arising out of your use of the software,
 including, but not limited to, the loss or corruption of your data or damages
 of any kind resulting from use of the software, any prohibited use, or your
 inability to use the software. You agree to defend, indemnify and hold harmless
 MBARI and its officers, directors, and employees against any claim, loss,
 liability or expense, including attorneys' fees, resulting from loss of or
 damage to property or the injury to or death of any person arising out of the
 use of the software.
 
 The MBARI software is provided without obligation on the part of the
 Monterey Bay Aquarium Research Institute to assist in its use, correction,
 modification, or enhancement.
 
 MBARI assumes no responsibility or liability for any third party and/or
 commercial software required for the database or applications. Licensee agrees
 to obtain and maintain valid licenses for any additional third party software
 required.
 */

/////////////////////////
// Headers 
/////////////////////////
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>

#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)

#elif defined(__WIN32) || defined(_WIN64)
#include <stdint.h>
#include <stdbool.h>

//#pragma message "Compiling __WIN32"
//define something for Windows (32-bit and 64-bit, this part is common)
#if _MSC_VER < 1900
#       define snprintf _snprintf
#endif //MSC_VER

#define WIN_DECLSPEC __declspec(dllimport)

#ifdef _WIN64
//define something for Windows (64-bit only)
#else // is WIN32
//define something for Windows (32-bit only)
#endif // WIN64

#elif defined(__unix__) || defined(__APPLE__) || defined(__CYGWIN__)
// POSIX
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif // POSIX

#include "cwglib.h"
#include "iowfile.h"
#include "licor8xx-shared.h"

/////////////////////////
// Macros
/////////////////////////

// These macros should only be defined for 
// application main files rather than general C files
/*
/// @def PRODUCT
/// @brief header software product name
#define PRODUCT "carbonwg"

/// @def COPYRIGHT
/// @brief header software copyright info
#define COPYRIGHT "Copyright 2002-2019 MBARI Monterey Bay Aquarium Research Institute, all rights reserved."
/// @def NOWARRANTY
/// @brief header software terms of use
#define NOWARRANTY  \
"This program is distributed in the hope that it will be useful,\n"\
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"\
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"\
"GNU General Public License for more details (http://www.gnu.org/licenses/gpl-3.0.html)\n"
*/


/////////////////////////
// Declarations 
/////////////////////////

/////////////////////////
// Imports
/////////////////////////

/////////////////////////
// Module Global Variables
/////////////////////////
char g_cwg_cmdbuf_mem[CWG_CMD_BUF_BYTES]={0};
char *g_cwg_cmdbuf=g_cwg_cmdbuf_mem;
bool g_cwg_interrupt=false;

/////////////////////////
// Function Definitions
/////////////////////////
#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)

#elif defined(__WIN32) || defined(_WIN64)

#elif defined(__unix__) || defined(__APPLE__) || defined(__CYGWIN__)

uint32_t cwg_upload_file(wser_t *self, char *dest, char *src, bool binary)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest && NULL!=src){
#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)
        FILE_T file_s, *fp=&file_s;
#else
        FILE_T *fp;
#endif
        char *dest_path=strdup(dest);
        char *cp=NULL;
        bool dpath_valid=true;
        if(strlen(dest_path)>12 ||
           ((cp=strstr(dest_path,"."))!=NULL && (cp-dest_path>8)) ){
            dpath_valid=false;
        }

        if(dpath_valid && iow_fopen(&fp,src,IOW_READ)==0){
            iow_fseek(fp,0);
            uint32_t src_len=iow_fsize(fp);
            char cmd_buf[CWG_CMD_BUF_BYTES]={0};
            char iobuf[CWG_IO_BUF_BYTES]={0};

            wser_write_read_ln(self, CMD_HOST_PROMPT_DIS, strlen(CMD_HOST_PROMPT_DIS), iobuf, CWG_IO_BUF_BYTES, CRLF, 1);
            wser_write_read_ln(self, CMD_HOST_ECHO_DIS, strlen(CMD_HOST_ECHO_DIS), iobuf, CWG_IO_BUF_BYTES, CRLF, 1);

            if(binary){
            wser_write_read_ln(self, CMD_MKCMD("%s q b:%"FMT_U32" T5 %s",CMD_UPLOAD,src_len,dest_path), CMD_LEN, cmd_buf, CWG_CMD_BUF_BYTES, NULL,1);
            }else{
            wser_write_read_ln(self, CMD_MKCMD("%s q T5 %s",CMD_UPLOAD,dest_path), CMD_LEN, cmd_buf, CWG_CMD_BUF_BYTES, NULL,1);
            }
            uint32_t bt=0;
            uint32_t btx=0;
            while(!iow_feof(fp)){
                memset(iobuf,0,CWG_IO_BUF_BYTES);
                if( (bt=iow_fread(fp,iobuf,CWG_IO_BUF_BYTES))>0){
                    wser_set_wt(self,2);
                    wser_write(self,iobuf,bt,NULL);
                    btx+=bt;
                }
                if(btx>=src_len){
                    break;
                }
            }

            wser_read_until(self, "BIN_EOT\r\n", cmd_buf, CWG_CMD_BUF_BYTES, 2+((2*btx)/1000));

            retval=btx;
            iow_fclose(fp);
        }else{
            // invalid path error
            OUT_ERR("destination path invalid %s%s",dest_path,LINEEND);
        }
        if(NULL!=dest_path){
            free(dest_path);
        }
    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_download_file(wser_t *self, char *dest, char *src, bool binary)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest && NULL!=src){

#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)
        FILE_T file_s, *fp=&file_s;
#else
        FILE_T *fp;
#endif

        if(iow_fopen(&fp,dest,IOW_CREATE_ALWAYS | IOW_WRITE | IOW_READ)==0){
            iow_fseek(fp,0);
            uint32_t src_len=0;
            char iobuf[CWG_IO_BUF_BYTES]={0};

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

            // get file size
            wser_write_read_ln(self, CMD_MKCMD("%s %s",CMD_FSIZE,src), CMD_LEN, iobuf, CWG_IO_BUF_BYTES, CRLF,1);

            if(strstr(iobuf,"-1")==NULL && sscanf(iobuf,"%"FMT_U32"",&src_len)==1){
//                OUT_CTTY("fsize ret[%"FMT_U32"]\r\n",src_len);
                memset(iobuf,0,CWG_IO_BUF_BYTES);
                wser_drain_rx(self,5);

                // send CAT request
                wser_set_wt(self,2);
                wser_write(self,CMD_MKCMD("%s rb: %s\r\n",CMD_CAT,src),CMD_LEN,NULL);

                // read until bytes received or end of input
                // TODO: this may need some hardening
                memset(iobuf,0,CWG_IO_BUF_BYTES);
                uint32_t br=0;
                uint32_t brx=0;
                int retries=4;
                while( brx<src_len && retries>0){
                    if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                        iow_fwrite(fp,iobuf,br);
                        brx+=br;
//                        OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                        memset(iobuf,0,CWG_IO_BUF_BYTES);
                        retries=4;
                    }else{
                        retries--;
                    }
                }
//                OUT_CTTY("DONE -br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                retval=brx;

                iow_fclose(fp);
            }else{
                // fsize error
                OUT_ERR("could not get size of file %s%s",src,LINEEND);
            }
        }else{
            // fopen error
            OUT_ERR("could not open file %s%s",src,LINEEND);
        }
    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_fget_lastn(wser_t *self, char *dest, int mode, char *src, uint32_t count, char *ofmt)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest){
#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)
        FILE_T file_s, *fp=&file_s;
#else
        FILE_T *fp;
#endif

        if(iow_fopen(&fp,dest, mode)==0){

            iow_fseek(fp,0);
            char iobuf[CWG_IO_BUF_BYTES]={0};

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

            memset(iobuf,0,CWG_IO_BUF_BYTES);
            wser_drain_rx(self,5);

            // send last sample (csv)...
            wser_set_wt(self,2);
            wser_write(self,CMD_MKCMD("%s Z l%"FMT_U32" dbg:0 out:%s %s\r\n",CMD_LCAT,count,ofmt,(NULL!=src?src:"")),CMD_LEN,NULL);

            // read until bytes received or end of input
            // TODO: this may need some hardening
            uint32_t br=0;
            uint32_t brx=0;
//            uint32_t src_len=count*LI_ZREC_SIZEN(count);
            int retries=CWG_FGET_LASTN_RETRIES;
            while( retries>0){
                if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES,(2+(count/2))))>0){
                    iow_fwrite(fp,iobuf,br);
                    brx+=br;
//                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                    memset(iobuf,0,CWG_IO_BUF_BYTES);
                    retries=CWG_FGET_LASTN_RETRIES;
                }else{
                    retries--;
                }
            }
//            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
            retval=brx;

            iow_fclose(fp);

        }else{
            // fopen error
            OUT_ERR("could not open file %s%s",src,LINEEND);
        }
    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_mget_lastn(wser_t *self, byte *dest, uint32_t len, char *src, uint32_t count, char *ofmt)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest && len>0){

        char iobuf[CWG_IO_BUF_BYTES]={0};

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

        memset(iobuf,0,CWG_IO_BUF_BYTES);
        wser_drain_rx(self,5);

        // send last sample (csv)...
        wser_set_wt(self,2);
        wser_write(self,CMD_MKCMD("%s Z l%"FMT_U32" dbg:0 out:%s %s\r\n",CMD_LCAT,count,ofmt,(NULL!=src?src:"")),CMD_LEN,NULL);

        // read until bytes received or end of input
        // TODO: this may need some hardening
        uint32_t br=0;
        uint32_t brx=0;
        //            uint32_t src_len=count*LI_ZREC_SIZEN(count);
        int retries=CWG_FGET_LASTN_RETRIES;
        byte *pdest = dest;
        while( retries>0 ){
            if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                if((pdest+br)<(dest+len)){
                    memcpy(pdest,iobuf,br);
                    pdest+=br;
                    brx+=br;
                }else{
                    uint32_t wlen = dest+len-pdest;
                    memcpy(pdest,iobuf,wlen);
                    pdest+=wlen;
                    brx+=wlen;
                    OUT_ERR("%s - buffer full brx %"FMT_U32" len %"FMT_U32" pofs %"FMT_U32"\r\n",__func__,brx,len,(uint32_t)(pdest-dest));
                    break;
                }
                //                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                memset(iobuf,0,CWG_IO_BUF_BYTES);
                retries=CWG_FGET_LASTN_RETRIES;
            }else{
                retries--;
            }
        }
        //            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
        retval=brx;

    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_fcget_lastn(wser_t *self, char *dest, int mode, char *src, uint32_t count)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest){
#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)
        FILE_T file_s, *fp=&file_s;
#else
        FILE_T *fp;
#endif

        if(iow_fopen(&fp,dest, mode)==0){

            iow_fseek(fp,0);
            char iobuf[CWG_IO_BUF_BYTES]={0};

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

            memset(iobuf,0,CWG_IO_BUF_BYTES);
            wser_drain_rx(self,5);

            // send last sample (csv)...
            wser_set_wt(self,2);
            wser_write(self,CMD_MKCMD("%s r:-,%"FMT_U32" %s\r\n",CMD_CAT,count,(NULL!=src?src:"")),CMD_LEN,NULL);

            // read until bytes received or end of input
            // TODO: this may need some hardening
            uint32_t br=0;
            uint32_t brx=0;
//            uint32_t src_len=count*LI_ZREC_SIZEN(count);
            int retries=CWG_FGET_LASTN_RETRIES;
            while( retries>0){
                if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                    iow_fwrite(fp,iobuf,br);
                    brx+=br;
//                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                    memset(iobuf,0,CWG_IO_BUF_BYTES);
                    retries=CWG_FGET_LASTN_RETRIES;
                }else{
                    retries--;
                }
            }
//            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
            retval=brx;

            iow_fclose(fp);

        }else{
            // fopen error
            OUT_ERR("could not open file %s%s",src,LINEEND);
        }
    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_mcget_lastn(wser_t *self, byte *dest, uint32_t len, char *src, uint32_t count)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest && len>0){

        char iobuf[CWG_IO_BUF_BYTES]={0};

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

        memset(iobuf,0,CWG_IO_BUF_BYTES);
        wser_drain_rx(self,5);

        // send last sample (csv)...
        wser_set_wt(self,2);
        wser_write(self,CMD_MKCMD("%s r:-,%"FMT_U32" %s\r\n",CMD_CAT,count,(NULL!=src?src:"")),CMD_LEN,NULL);

        // read until bytes received or end of input
        // TODO: this may need some hardening
        uint32_t br=0;
        uint32_t brx=0;
        //            uint32_t src_len=count*LI_ZREC_SIZEN(count);
        int retries=CWG_FGET_LASTN_RETRIES;
        byte *pdest = dest;
        while( retries>0 ){
            if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                if((pdest+br)<(dest+len)){
                    memcpy(pdest,iobuf,br);
                    pdest+=br;
                    brx+=br;
                }else{
                    uint32_t wlen = dest+len-pdest;
                    memcpy(pdest,iobuf,wlen);
                    pdest+=wlen;
                    brx+=wlen;
                    OUT_ERR("%s - buffer full brx %"FMT_U32" len %"FMT_U32" pofs %"FMT_U32"\r\n",__func__,brx,len,(uint32_t)(pdest-dest));
                    break;
                }
                //                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                memset(iobuf,0,CWG_IO_BUF_BYTES);
                retries=CWG_FGET_LASTN_RETRIES;
            }else{
                retries--;
            }
        }
        //            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
        retval=brx;

    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_fget_n(wser_t *self, char *dest, int mode, char *src, uint32_t start, uint32_t count, char *ofmt)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest){
#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)
        FILE_T file_s, *fp=&file_s;
#else
        FILE_T *fp;
#endif

        if(iow_fopen(&fp,dest, mode)==0){

            iow_fseek(fp,0);
            char iobuf[CWG_IO_BUF_BYTES]={0};

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

            memset(iobuf,0,CWG_IO_BUF_BYTES);
            wser_drain_rx(self,5);

            // send last sample (csv)...
            wser_set_wt(self,2);
            wser_write(self,CMD_MKCMD("%s Z s%"FMT_U32" c%"FMT_U32" dbg:0 out:%s %s\r\n",CMD_LCAT,start,count,ofmt,(NULL!=src?src:"")),CMD_LEN, NULL);

            // read until bytes received or end of input
            // TODO: this may need some hardening
            uint32_t br=0;
            uint32_t brx=0;
            //            uint32_t src_len=count*LI_ZREC_SIZEN(count);
            int retries=CWG_FGET_LASTN_RETRIES;
            while( retries>0){
                if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                    iow_fwrite(fp,iobuf,br);
                    brx+=br;
                    //                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                    memset(iobuf,0,CWG_IO_BUF_BYTES);
                    retries=CWG_FGET_LASTN_RETRIES;
                }else{
                    retries--;
                }
            }
            //            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
            retval=brx;

            iow_fclose(fp);

        }else{
            // fopen error
            OUT_ERR("could not open file %s%s",src,LINEEND);
        }
    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_mget_n(wser_t *self, byte *dest, uint32_t len, char *src, uint32_t start, uint32_t count, char *ofmt)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest && len>0){

        char iobuf[CWG_IO_BUF_BYTES]={0};

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

        memset(iobuf,0,CWG_IO_BUF_BYTES);
        wser_drain_rx(self,5);

        // send last sample (csv)...
            wser_set_wt(self,2);
            wser_write(self,CMD_MKCMD("%s Z s%"FMT_U32" c%"FMT_U32" dbg:0 out:%s %s\r\n",CMD_LCAT,start,count,ofmt,(NULL!=src?src:"")),CMD_LEN, NULL);

        // read until bytes received or end of input
        // TODO: this may need some hardening
        uint32_t br=0;
        uint32_t brx=0;
        //            uint32_t src_len=count*LI_ZREC_SIZEN(count);
        int retries=CWG_FGET_LASTN_RETRIES;
        byte *pdest = dest;
        while( retries>0 ){
            if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                if((pdest+br)<(dest+len)){
                    memcpy(pdest,iobuf,br);
                    pdest+=br;
                    brx+=br;
                }else{
                    uint32_t wlen = dest+len-pdest;
                    memcpy(pdest,iobuf,wlen);
                    pdest+=wlen;
                    brx+=wlen;
                    OUT_ERR("%s - buffer full brx %"FMT_U32" len %"FMT_U32" pofs %"FMT_U32"\r\n",__func__,brx,len,(uint32_t)(pdest-dest));
                    break;
                }
                //                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                memset(iobuf,0,CWG_IO_BUF_BYTES);
                retries=CWG_FGET_LASTN_RETRIES;
            }else{
                retries--;
            }
        }
        //            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
        retval=brx;

    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_mcget_n(wser_t *self, byte *dest, uint32_t len, char *src, uint32_t start, uint32_t count)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest && len>0){

        char iobuf[CWG_IO_BUF_BYTES]={0};

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

        memset(iobuf,0,CWG_IO_BUF_BYTES);
        wser_drain_rx(self,5);

        // send last sample (csv)...
            wser_set_wt(self,2);
            wser_write(self,CMD_MKCMD("%s r:l,%"FMT_U32",l,%"FMT_U32" %s\r\n",CMD_CAT,start,count,(NULL!=src?src:"")),CMD_LEN, NULL);

        // read until bytes received or end of input
        // TODO: this may need some hardening
        uint32_t br=0;
        uint32_t brx=0;
        //            uint32_t src_len=count*LI_ZREC_SIZEN(count);
        int retries=CWG_FGET_LASTN_RETRIES;
        byte *pdest = dest;
        while( retries>0 ){
            if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                if((pdest+br)<(dest+len)){
                    memcpy(pdest,iobuf,br);
                    pdest+=br;
                    brx+=br;
                }else{
                    uint32_t wlen = dest+len-pdest;
                    memcpy(pdest,iobuf,wlen);
                    pdest+=wlen;
                    brx+=wlen;
                    OUT_ERR("%s - buffer full brx %"FMT_U32" len %"FMT_U32" pofs %"FMT_U32"\r\n",__func__,brx,len,(uint32_t)(pdest-dest));
                    break;
                }
                //                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                memset(iobuf,0,CWG_IO_BUF_BYTES);
                retries=CWG_FGET_LASTN_RETRIES;
            }else{
                retries--;
            }
        }
        //            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
        retval=brx;

    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

uint32_t cwg_fcget_n(wser_t *self, char *dest, int mode, char *src, uint32_t start, uint32_t count)
{
    uint32_t retval=0;
    if(NULL!=self && NULL!=dest){
#if defined(__PIC24FJ256GA106__) || defined(__PIC24FJ256GA606__) || defined(__PIC24FJ1024GA606__)
        FILE_T file_s, *fp=&file_s;
#else
        FILE_T *fp;
#endif

        if(iow_fopen(&fp,dest, mode)==0){

            iow_fseek(fp,0);
            char iobuf[CWG_IO_BUF_BYTES]={0};

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

            memset(iobuf,0,CWG_IO_BUF_BYTES);
            wser_drain_rx(self,5);

            // send last sample (csv)...
            wser_set_wt(self,2);
            wser_write(self,CMD_MKCMD("%s r:l,%"FMT_U32",l,%"FMT_U32" %s\r\n",CMD_CAT,start,count,(NULL!=src?src:"")),CMD_LEN, NULL);

            // read until bytes received or end of input
            // TODO: this may need some hardening
            uint32_t br=0;
            uint32_t brx=0;
            //            uint32_t src_len=count*LI_ZREC_SIZEN(count);
            int retries=CWG_FGET_LASTN_RETRIES;
            while( retries>0){
                if((br=wser_read_until(self, NULL, iobuf, CWG_IO_BUF_BYTES, 2))>0){
                    iow_fwrite(fp,iobuf,br);
                    brx+=br;
                    //                    OUT_CTTY("br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
                    memset(iobuf,0,CWG_IO_BUF_BYTES);
                    retries=CWG_FGET_LASTN_RETRIES;
                }else{
                    retries--;
                }
            }
            //            OUT_CTTY("DONE - br/brx/slen[%"FMT_U32"/%"FMT_U32"/%"FMT_U32"]\r\n",br,brx,src_len);
            retval=brx;

            iow_fclose(fp);

        }else{
            // fopen error
            OUT_ERR("could not open file %s%s",src,LINEEND);
        }
    }else{
        OUT_ERR("invalid argument %s%s",src,LINEEND);
    }
    return retval;
}

#endif // platform (POSIX)

void cwg_break(bool enable)
{
    g_cwg_interrupt=enable;
}


