/// @file cwgsys.h
/// @authors k. headley
/// @date 05 dec 2018
/// Carbon Waveglider system
/// @sa doxygen-examples.c for more examples of Doxygen markup

/// Copyright Information
/// Copyright 2002-2017 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.

/// Always do this
#ifndef CWGSYS_H
#define CWGSYS_H
/// Includes 
#include <time.h>
#include <stdint.h>
#include "ff.h"

/// Macros

#ifndef STR
/// @def STR(s)
/// @brief string helper (string-ize s)
/// @param s string
#define STR(s) #s
#endif

#ifndef XSTR
/// @def XSTR(s)
/// @brief string helper (string-ize s)
/// @param s string
#define XSTR(s) STR(s)
#endif

#ifndef SW_VERSION
/// @def SYS_SW_VERSION_STR
/// @brief software version default (typically defined a compile time)
#define SYS_SW_VERSION_STR "UNDEFINED"
#else
/// @def SYS_SW_VERSION_STR
/// @brief software version default (typically defined a compile time)
#define SYS_SW_VERSION_STR XSTR(SW_VERSION)
#endif
#ifndef SW_TAG
/// @def SYS_SW_TAG_STR
/// @brief software tag default (typically defined a compile time)
#define SYS_SW_TAG_STR "UNDEFINED"
#else
/// @def SYS_SW_TAG_STR
/// @brief software tag default (typically defined a compile time)
#define SYS_SW_TAG_STR XSTR(SW_TAG)
#endif
#ifndef SW_CONFIG
/// @def SYS_SW_CONFIG_STR
/// @brief software configuration default (typically defined a compile time)
#define SYS_SW_CONFIG_STR "UNDEFINED"
#else
/// @def SYS_SW_CONFIG_STR
/// @brief software configuration default (typically defined a compile time)
#define SYS_SW_CONFIG_STR XSTR(SW_CONFIG)
#endif

#ifndef HW_SERIAL_NUMBER
/// @def SYS_HW_SERIAL_NUMBER
/// @brief software serial number (may be defined at compile time)
/// this is temporary measure until hardware EEPROM implementation
#define SYS_HW_SERIAL_NUMBER 0xFFFF
#endif

/// @def SYS_BOOSTRAP_DFL
/// @brief system bootstrap script name
#define SYS_BOOSTRAP_DFL "SYSBOOT.SCR" 
/// @def SYS_CONFIG_DFL
/// @brief system config file name
#define SYS_CONFIG_DFL "CONFIG.TXT"
/// @def SYS_HELP_DFL
/// @brief system help file name
#define SYS_HELP_DFL "HELP.MD"
/// @def SYS_CRONMAN_DFL
/// @brief cron help file name
#define SYS_CRONMAN_DFL "CRON.MAN"

/// @def CMD_LIST_INDENT_DFL
/// @brief command list indent (spaces)
#define CMD_LIST_INDENT_DFL 2
/// @def SYS_MAX_SLEEP_MS
/// @brief max default sleep interval (msec)
#define SYS_MAX_SLEEP_MS 0xFFFFFFFFUL
/// @def SYS_CRON_SLEEP_MARGIN_MSEC
/// @brief wake up early for cron tasks
//#define SYS_CRON_SLEEP_MARGIN_MSEC 3000UL
  
// palloc buffer pool sizes
#define POOL_16_COUNT   16 
#define POOL_32_COUNT   16 
#define POOL_64_COUNT   3
#define POOL_128_COUNT  3
#define POOL_256_COUNT  2
// serPrintf:g_ser_msg_buffer uses 512 
// could be smaller if not printing
// large strings. Full raw licor messages
// ~365 bytes
#define POOL_512_COUNT  2
// 1024 needed for line count
#define POOL_1024_COUNT 1
// 2048 needed for log pager
#define POOL_2048_COUNT 0

/// @def SYS_LED_ON_CMD
/// @brief LED blink ON
#define SYS_LED_ON_CMD()   doSetBlink(HI)

/// @def HOST_XCVR_ON
/// @brief enable host port transceiver
#define HOST_XCVR_ON()  doSetBit(XCVR_HOST, HI)
/// @def HOST_XCVR_OFF
/// @brief disable host port transceiver
#define HOST_XCVR_OFF() doSetBit(XCVR_HOST, LO)
/// @def CONS_XCVR_ON
/// @brief enable console port transceiver
#define CONS_XCVR_ON()  doSetBit(XCVR_CONS, HI)
/// @def CONS_XCVR_OFF
/// @brief disable console port transceiver
#define CONS_XCVR_OFF() doSetBit(XCVR_CONS, LO)

/// @def USE_MCC_CHIP_CONFIG
/// @brief use MCC configuration pragmas (recommended)
#define USE_MCC_CHIP_CONFIG
/// @def WITH_SDCARD_DETECT
/// @brief enable SD card detection (unreliable)
#undef WITH_SDCARD_DETECT
/// @def WITH_UI_ECHO
/// @brief enable user interface character echo
#undef WITH_UI_ECHO

#ifndef WITHOUT_IOF_LESS
/// @def WITH_IOF_LESS
/// @brief enable LESS file pager
#define WITH_IOF_LESS
#endif

/// @def UI_CMD_BUF_BYTES
/// @brief UI max command line bytes 
/// undefine to use UI module default
#define UI_CMD_BUF_BYTES   128   

/// @def WITH_UI_HISTORY
/// @brief enable support for history buffer
#define WITH_UI_HISTORY

/// @def UI_HIST_QUEUE_LEN
/// @brief history queue length (entries)
/// each uses UI_CMD_BUF_BYTES memory
/// undefine to use UI module default
#define UI_HIST_QUEUE_LEN 16

/// @def WITH_MDIO_SHOW
/// @brief enable support for MDIO SHOW option
#define WITH_MDIO_SHOW

/// @def WITH_MDIO_SHOW
/// @brief enable support for MICRON scheduler
#define WITH_MICRON

/// @def WITH_MDIO_SHOW
/// @brief enable code prototyping area (proto.c,h)
/// (enable PROTO_<X> features separately)
#define WITH_PROTO
#ifdef WITH_PROTO
//#define PROTO_SIZES
//#define PROTO_CONFIG
//#define PROTO_PALLOC
//#define PROTO_SCRIPT
//#define PROTO_TOKENIZE
//#define PROTO_SCHEDULE
//#define PROTO_SCHEDULE_DEMO
//#define PROTO_CRON
//#define PROTO_TASK
//#define PROTO_NMEAS
//#define PROTO_QUEUE
//#define PROTO_BUG_STRUCT_ALIGN
//#define PROTO_UI_TOKENIZER
//#define PROTO_FLAG_MNEM
//#define PROTO_TRAP_TEST
//#define PROTO_HEXSHOW_TEST
//#define PROTO_LESS_TEST
//#define PROTO_SEEK_TEST
//#define PROTO_MAXSEG
//#define PROTO_MBUF
//#define PROTO_DATA_SIZES
//#define PROTO_Z85
//#define PROTO_MKBLOG
//#define PROTO_PROGVARS
//#define PROTO_SEQ_API
//#define PROTO_SEQ_USR
//#define PROTO_SUMMARIZER
//#define PROTO_SHT3X
#define PROTO_X
/// @def PROTO_TEST
/// @brief enable proto_test option
#define PROTO_TEST(arg) proto_test(arg)
#else
/// @def PROTO_TEST
/// @brief enable proto_test option
#define PROTO_TEST(arg) 
#endif

/// @def WITH_SHT3X
/// @brief enable SHT3X RH/T sensor peripheral
//#define WITH_SHT3X

/// @def WITH_SPI
/// @brief enable SPI peripherals (recommended)
#define WITH_SPI
/// @def WITH_ADC
/// @brief enable ADC peripherals (recommended)
#define WITH_ADC
/// define WITH_DIO
#ifdef WITH_SPI
/// @def WITH_RTC
/// @brief enable RTC peripherals (recommended, requires SPI)
#define WITH_RTC
/// @def WITH_SDCARD
/// @brief enable SD card (recommended, requires SPI)
#define WITH_SDCARD
#endif

#ifdef WITH_SDCARD
/// @def WITH_LOGGING
/// @brief enable LOGGING (recommended, requires SDCARD, SPI)
#define WITH_LOGGING
#endif

/// @def WITH_LICOR_STREAMX_RESTORE_ORATE
/// @brief enable output rate restore after li-cor measurement (unreliable) 
#undef WITH_LICOR_STREAMX_RESTORE_ORATE

/// @def WITH_TELEM
/// @brief enable telemetry (legacy, not implemented)
#undef WITH_TELEM
/// @def WITH_OXY
/// @brief enable dissolved O2 (legacy, not implemented)
#undef WITH_OXY
/// @def WITH_PH
/// @brief enable pH (legacy, not implemented)
#undef WITH_PH

/// @def USER_TIME_OUT
/// @brief allow sleep if no console input for USER_TIME_OUT msec
#define USER_TIME_OUT   30000UL
/// @def SYS_MIN_SLEEP_MSEC
/// @brief allow sleep if no task to run in this many ms. 
/// must be more than TMR1 period (set via PR1 using T1CONbits.TCKPS, RTCFREQ)
#define SYS_MIN_SLEEP_MSEC   12000UL
/// @def HI
/// @brief set a bit, or turn something on
#define HI      1
/// @def LO
/// @brief clear a bir or turn something off
#define LO      0
/// @def ON
/// @brief set a bit, or turn something on
#define ON      1
/// @def OFF
/// @brief clear a bir or turn something off
#define OFF     0
/// @def NUMBER_OF(x)
/// @brief determine number of elements in an array
/// @param p array pointer
#define NUMBER_OF(p) (sizeof(p)/sizeof(p[0]))
/// @def DESPACE(p)
/// @brief move a char* past spaces
/// @param p character pointer
#define DESPACE(p)  while( (NULL!=p) && (' '==*p) ) {p++;}

/// @def ISQUOTE(c)
/// @brief true if c is single or double quote
/// @param c character
#define ISQUOTE(c) (c==0x22 || c==0x27)

/// @def PORT_VALID(v)
/// @brief true if v is a valid port handle (enum)
/// @param v port index/handle
#define PORT_VALID(v) (v>=0 && v<UART_COUNT ? true : false)

/// Type Definitions

/// @enum serial_port_t
/// @brief serial port enumeration/mapping
/// UART1
/// UART2
/// UART3
/// port count
typedef enum {
    SER_INVALID=-2,
    SER_SCR=-1,
    SER_HOST=0,
    SER_LICOR,
    SER_CONS,
    UART_COUNT
}serial_port_t;

/// @enum io_bit_t
/// @brief IO bit
/// SVnA, SVnB   valve n positions
/// PUMP0_DC     pump power (12V)
/// PUMP1_DC     pump power (12V)
/// ADC1         A/D converter 1 power (5V)
/// ADC2         A/D converter 2 power (5V)
/// LICOR_DC     Licor power (12V)
/// XCVR_HOST    host    RS232 transceiver enable
/// XCVR_LICOR   licor   RS232 transceiver enable
/// XCVR_CONSOLE console RS232 transceiver enable

typedef enum {
    SV0A = 0,
    SV0B,
    SV1A,
    SV1B,
    SV2A,
    SV2B,
    SV3A,
    SV3B,
    SV4A,
    SV4B,
    SV5A,
    SV5B,
    SV6A,
    SV6B,
    SV7A,
    SV7B,
    SV8A,
    SV8B,
    SV9A,
    SV9B,
    PUMP0_DC,
    PUMP1_DC,
    PUMP2_DC,
    PUMP3_DC,
    LICOR_DC,
    ADC0,
    ADC1,
    ADC2,
    XCVR_HOST,
    XCVR_LICOR,
    XCVR_CONS,
    IO_BITS
}io_bit_t;

/// @def SV_COUNT
/// @brief valve port count
#define SV_COUNT 10
/// @def IO_SV_ALL
/// @brief IO mask: all valve ports
#define IO_SV_ALL      0x000FFFFFUL
/// @def IO_PUMP_ALL
/// @brief IO mask: all pump ports
#define IO_PUMP_ALL    0x00F00000UL
/// @def IO_PUMP_AIR
/// @brief IO mask: air pump port(s)
#define IO_PUMP_AIR    0x00100000UL
/// @def IO_PUMP_SAMPLE
/// @brief IO mask: sample pump port(s)
#define IO_PUMP_SAMPLE 0x00200000UL
/// @def IO_PUMP_ACID
/// @brief IO mask: acid pump port(s)
#define IO_PUMP_ACID   0x00400000UL
/// @def IO_PUMP_SEA
/// @brief IO mask: sea water pump port(s)
#define IO_PUMP_SEA    0x00800000UL
/// @def IO_PUMP_0
/// @brief IO mask: pump_0
#define IO_PUMP_0      0x00100000UL
/// @def IO_PUMP_1
/// @brief IO mask: pump_1
#define IO_PUMP_1      0x00200000UL
/// @def IO_PUMP_2
/// @brief IO mask: pump_2
#define IO_PUMP_2      0x00400000UL
/// @def IO_PUMP_3
/// @brief IO mask: pump_3
#define IO_PUMP_3      0x00800000UL
/// @def IO_LICOR_DC
/// @brief IO mask: LI-COR DC power
#define IO_LICOR_DC    0x01000000UL
/// @def IO_AD0_EN
/// @brief IO mask: ADC0 enable
#define IO_AD0_EN      0x02000000UL
/// @def IO_AD1_EN
/// @brief IO mask: ADC1 enable
#define IO_AD1_EN      0x04000000UL
/// @def IO_ADC_ALL
/// @brief IO mask: ADC enable(s)
#define IO_ADC_ALL     0x06000000UL
/// @def IO_PROTECTED
/// @brief IO mask: protected ports
#define IO_PROTECTED   0xD8000000UL
/// @def IO_ALL
/// @brief IO mask: all IO ports
#define IO_ALL         0x7FFFFFFFUL
/// @def LICOR_PUMP_DC
/// @brief IO mask: LI-COR pump power
#define LICOR_PUMP_DC  PUMP0_DC
/// @def MBIT(b) 
/// @brief returns 1UL left-shifted b places
/// @param b number of places to shift
#define MBIT(b)  (1UL<<b)

/// @def typedef struct sys_state_s sys_state_t
/// @brief system state structure 
/// for future state persistence feature
typedef struct sys_state_s{
    /// @var sys_state_s::t_last_sample
    /// @brief last sample timestamp
    uint64_t t_last_sample;
    /// @var sys_state_s::t_last_cal
    /// @brief last cal sample number
    uint64_t t_last_cal;
    /// @var sys_state_s::t_last_request
    /// @brief last request timestamp
    uint64_t t_last_request;
    /// @var sys_state_s::power_cycles
    /// @brief number of power cycles
    uint32_t power_cycles;
    /// @var sys_state_s::sample_cycles
    /// @brief number of sample cycles
    uint32_t sample_cycles;
    /// @var sys_state_s::cal_cycles
    /// @brief number of cal cycles
    uint32_t cal_cycles;
}sys_state_t;

/// Exports

#ifdef __cplusplus
extern "C" {
#endif
   
    /// @var uint16_t g_rcon
    /// @brief global reset status register value
    extern uint16_t g_rcon;
    /// @var serial_port_t g_ctty
    /// @brief controlling console handle
    extern serial_port_t g_ctty;

    /// @fn return_code_t sys_init()
    /// @brief initialize system (palloc memory, etc.)
    /// Do after hw init
    return_code_t sys_init();

    /// @fn void *palloc(size_t len)
    /// @brief allocate smallest appropriate fixed-size buffer from pool.
    /// Caller must release buffer using pfree. Buffers are statically allocated.
    /// Buffers are NULL filled.
    /// @param[in]  len buffer size (bytes)  
   /// @return pointer to buffer on success, NULL otherwise (if no buffer large enough is available)
    void *palloc(size_t len);
    /// @fn void pfree(void *ptr)
    /// @brief Release buffer allocated using palloc.
    /// @param[in]  ptr pointer to buffer allocated using palloc
    /// @return none
    void pfree(void *ptr);
    /// @fn char *pstrdup(const char *src)
    /// @brief Copy a string into a palloc buffer.
    /// Caller must release buffer using pfree. 
    /// @param[in]  src string to copy
    /// @return pointer to new buffer on success, NULL otherwise
   /// char *pstrdup(const char *src);
   #define pstrdup(src) ptstrdup(src, false, false)
    /// @fn char *ptstrdup(const char *src, bool trim_leading, bool trim_trailing)
    /// @brief Copy a string into a palloc buffer, trim leading/trailing whitespace.
    /// Caller must release buffer using pfree. 
    /// @param[in]  src string to copy
    /// @return pointer to new buffer on success, NULL otherwise
   char *ptstrdup(const char *src, bool trim_leading, bool trim_trailing);
    /// @fn char *pstralloc(char *start, char *end)
    /// @brief Copy bytes from start to end into a NULL terminated string in a palloc buffer.
    /// Caller must release buffer using pfree. 
    /// @param[in]  start start of bytes to copy
    /// @param[in]  end last byte
    /// @return pointer to new buffer on success, NULL otherwise
    char *pstralloc(char *start, char *end);

    /// @fn char *pargcat(int argc, char **argv, char *sep)
    /// @brief concatenate arg list to palloc string.
    /// Caller must release buffer using pfree. 
    /// @param[in]  argc list len
    /// @param[in]  argv strings list
    /// @param[in]  sep separator
    /// @return pointer to new buffer on success, NULL otherwise
    char *pargcat(int argc, char **argv, char *sep);

    /// @fn return_code_t pshow(char *arg)
    /// @brief show palloc memory
    /// @param[in]  arg unused (included for cmd_func compatibility)
    /// @return ERR_SUCCESS on success, ERR_FAILURE otherwise
    return_code_t pshow(int argc, char **argv);

    /// @fn tbd
    /// @brief tbd
    /// @param[in]  tbd
    /// @return on success, otherwise
   uint32_t sys_count_lines(char* arg, uint32_t *ms_out);

   /// @fn tbd
   /// @brief tbd
   /// @param[in]  tbd
   /// @return on success, otherwise
   void sys_show_tokens(const char *caller, int argc, char **argv);

   /// @fn tbd
   /// @brief tbd
   /// @param[in]  tbd
   /// @return on success, otherwise
  void sys_set_sdc_ok(bool is_ok);
  
  /// @fn tbd
  /// @brief tbd
  /// @param[in]  tbd
  /// @return on success, otherwise
  bool sys_sdc_ok();
  
  /// @fn uint16_t sys_hw_serial_number()
  /// @brief get hardware serial number
  /// @return serial number on success, 0xFFFF (unassigned) otherwise
  uint16_t sys_hw_serial_number();
  
  /// @fn uint16_t sys_sw_version()
  /// @brief get software version string
  /// @return software version on success, "UNDEFINED" otherwise
  const char *sys_sw_version();

  /// @fn uint16_t sys_sw_config()
  /// @brief get software config string
  /// @return software version on success, "UNDEFINED" otherwise
  const char *sys_sw_config();
  
  /// @fn void sys_banner()
  /// @brief print system banner to console
  /// @return none
  void sys_banner();
  
  /// @fn uint32_t sys_next_event()
  /// @brief return time until next scheduled event
  /// @return time until next scheduled event (msec)
  uint32_t sys_next_event();

 #ifdef __cplusplus
}
#endif

#endif /// THIS_FILE