/*
 * David Muller; Germán Alfaro
 * davehmuller@gmail.com; alfaro.germanevera@gmail.com
 *
 * Thom Maughan; tm@mbari.org  2018...
 */


#ifndef MPHOX_SYSTEM_H_
#define MPHOX_SYSTEM_H_

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>

#if BOARD_MFET >= 1 || BOARD_MPHOX == 1
#include "inc/tm4c123gh6pge.h"
#endif
#if BOARD_NANOFET == 1
#include "inc/tm4c123gh6pm.h"
#endif

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_hibernate.h"

#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/eeprom.h"
#include "driverlib/gpio.h"
#include "driverlib/hibernate.h"
#include "driverlib/ssi.h"
#include "driverlib/interrupt.h"


//V=I*R => V=I*15K => I=V/15K amps => I=V*10^9/15K nano-Amps => I=V*66.6k nA => 15uV/nA.
#define COUNTERELECTRODE_IK_SCALE       66666.667   // 10^9/15K MCAP has 15K resistor, Ik
//
#define SUBSTRATECURRENT_IB_SCALING     1000        // 10^9/1M = 1000   MCAP has 1M resistor for Ib, substrate current

#define SIZEOF_PRNBUF  1020

#if BOARD_MFET == 1
#define 	VERSION		"v3.7.1 was the last support for MFET v1"     // MFET software version   Glider is 9600 baud
// battery backed HIB, no FRAM
// only one can be set to 1.  HIB uses battery backed ram in hibernate module, EEPROM uses onchip EEPROM with 500K cycles, FRAM requires 24CL04B chip on MFET v2
#define NONVOLATILEMEM  "Nonvol mem: Hibernate module battery backed RAM"
#define EEPROM_REG_STORE 0      // old, wear out EEPROM
#define HIB_REG_STORE   1       // used to turn on HIB register store to prevent EEPROM wearout
#define FRAM_REG_STORE  0
#endif
#if BOARD_MFET == 2
#define     VERSION     "v4.1.0 MFET revC"     // MFET software version   Glider is 9600 baud
// FRAM (and battery backed HIB)
#define NONVOLATILEMEM  "Nonvol mem: i2c Ferroelectric RAM"
#define EEPROM_REG_STORE 0      // old, wear out EEPROM
#define HIB_REG_STORE   0       // used to turn on HIB register store to prevent EEPROM wearout
#define FRAM_REG_STORE  2       // was 1, 2 means use of sys_samp
#endif
#if BOARD_MPHOX == 1
#define     VERSION     "v4.1.0 MpHOx revB"     // MFET software version   Glider is 9600 baud
// FRAM (and battery backed HIB)
#define NONVOLATILEMEM  "Nonvol mem: i2c Ferroelectric RAM"
#define EEPROM_REG_STORE 0      // old, wear out EEPROM
#define HIB_REG_STORE   0       // used to turn on HIB register store to prevent EEPROM wearout
#define FRAM_REG_STORE  2       // was 1 (sys_samp)
#endif
#if BOARD_NANOFET == 1
#define     VERSION     "v4.1.0 NanoFET pre-release"     // MFET software version   Glider is 9600 baud
// FRAM (and battery backed HIB)
#define NONVOLATILEMEM  "Nonvol mem: i2c Ferroelectric RAM"
#define EEPROM_REG_STORE 0      // old, wear out EEPROM
#define HIB_REG_STORE   0       // used to turn on HIB register store to prevent EEPROM wearout
#define FRAM_REG_STORE  2
#endif
#ifndef VERSION
#define     VERSION     "COMPILER FLAGS BOARD_MFET or BOARD_MPHOX or BOARD NANOFET NOT DEFINED"
#endif

#define NOMINAL_SAMPLE_TIMES    1
#define FAST_SAMPLE_TIMES       0


/* Boolean type */
typedef enum { FALSE = 0, TRUE } BOOL;
typedef enum {IDLE, START, DEPLOYED, COMMAND} deploy_state;
typedef enum {NORMAL=1, VERBOSE} output_mode;

/*
 * Delay lengths for SysCtlDelay().
 */
#define CLOCKSPEED 50000000.0  						//clock is set to run at 50MHZ
#define ONESEC (int)ceil((CLOCKSPEED/3.0))  		//SysCtlDelay takes 3 cycles per loop...so delay = DesiredDelayTimeInSeconds/((1/CLOCKSPEED)*3)
#define MILLISECOND (int)ceil((.001 / ((1.0/CLOCKSPEED)*3.0)))
#define MICROSECOND (int)ceil((.000001 / ((1.0/CLOCKSPEED)*3.0)))

/*
 * Buffer lengths.
 */
#define TIMESTAMPLENGTH 		50
#define INSTRUMENTBUFFSIZE 		400
#define MICROCAT_BUFFER_SIZE 	128
#define DBG_UART_BUFFER_SIZE    128     // buffer defined in microcat.h microcat sbe37 is on uart4
#define OPTODE_BUFFER_SIZE 		128     // buffer defined in optode.h optode is on uart3
#define CTD_BUFFER_SIZE         128
#define AUX1_BUFFER_SIZE		128
#define AUX2_BUFFER_SIZE		128
#define OCR_BUFFER_SIZE         128

#define GDATA_BYTES				512	// Number of bytes to read out with gdata command

#define IS_PRESENT		  1
#define NOT_PRESENT 	  0



/*
 * Constants
 */
#define R_			8.31451			// Univ gas constant
#define F_ 			96487			// Faraday constant
#define dEoINT_dt	-0.0011012		// Temperature coefficient for internal reference [Volts/C]
#define dEoEXT_dt	-0.0010482		// Temeprature coefficient for external reference [Volts/C]
#define LN10		2.302585		// Natural log of 10

// Standard deviation array values
#define SD_AVG		5
#define SD_MEAN		SD_AVG
#define SD_DIFF_SQ	SD_AVG+1
#define SD_VALUES	5

// AD1248 24-bit A/D defines
// signed 24bit numeric range is: -8,388608 to +8,388607
#define TWOTOTHE23 8388608  // 2 to the 23rd = 8388608
#define COUNTSTOVOLTS (float) (2.048 / (TWOTOTHE23 - 1))  //each count returned from the ADC has a weight of (Vref/PGA)/(2^23 -1 ).  We use PGA = 1.
#define PGA_1		0x00
#define PGA_2		0x10
#define PGA_4		0x20
#define PGA_8		0x30
#define PGA_16		0x40
#define PGA_32		0x50
#define PGA_64		0x60
#define PGA_128		0x70

#define SPS_5		0x00
#define SPS_10		0x01
#define SPS_20		0x02
#define SPS_40		0x03
#define SPS_80		0x04
#define SPS_160		0x05
#define SPS_320		0x06
#define SPS_640		0x07
#define SPS_1000	0x08
#define SPS_2000	0x09

#define VTHERM_TRIALS   5
#define VTHERM_SPS      20

#define VRSI_TRIALS     10
#define VRSI_SPS        20

#define VRSE_TRIALS     10
#define VRSE_SPS        20

#define IK_TRIALS       1
#define IK_SPS          20

#define VK_TRIALS       5
#define VK_SPS          20

#define IB_TRIALS       1
#define IB_SPS          20

#define VB_TRIALS       5
#define VB_SPS          20

#define VBIAS_TRIALS   1
#define VBIAS_SPS      40






/*
 * Definition of a structure containing the controller's parameters
 * These parameters are all modifiable by external user except where noted.
 * Structure is stored in EEPROM during hibernation.
 */
#define MAX_NUMOF_CONFIG_FIELDS         32  //was 30  These are for sampling / data logging configuration A-Z, 0-9
#define MAX_NUMOF_APP_CONFIG_FIELDS     16  // was 8 in 4.0.7

#define MAX_FILENAME        16      // 8.3 filename plus padding 24      //80 is too much, should be 32 or 40 at most.
#define MAX_USER_INITIALS   8
#define MAX_TESTER_NAME     48
#define MAX_VERSION_SIZE    32

#define MAX_BOARD_SN        24      //30

#define MAX_MCAP_SN         24      //30
#define MAX_PACKAGE_NAME    32      //30
#define MAX_DURAFET_SN      24      //30
#define MAX_CAPADAP_SN      24      //30
#define MAX_ISE_SN          24      //30
#define MAX_OPTODE_SN       24      //30
#define MAX_CTD_SN          24      //30
#define MAX_PUMP_SN         24      //30
#define MAX_BOARD_FABNOTE   80
#define MAX_DEPLOY_NOTE     80

// pump_sequencing types for selecting sequencing statemachine
#define TYPE_PUMP_NOTDEFD       0
#define TYPE_PUMP_SINGLE        1
#define TYPE_2PUMP_BEAMSV1      2
#define TYPE_PUMP_SELFCAL       3
#define TYPE_2PUMP_BEAMSV2      4




struct qaData
{
    uint32_t    microSD;            // microSD
    uint32_t    time;               // time of QA
    uint32_t    test_time;          // time it took to run QA
    uint32_t    eeprom;             // size of sys_data in eeprom, 0 if there is a problem
    uint32_t    sys_data_init;      // was the data initialized
    uint32_t    fram;
    uint32_t    adc12onchip;
    uint32_t    adc24;              // how many of the ADC fields are out of expected Jensenian range


    float    Vrsi;
    float    Vrsi_std;
    float    Vrsi_err;
    float    Vrse;
    float    Vrse_std;
    float    Vrse_err;
    float    Vtherm;
    float    Vtherm_std;
    float    Vtherm_err;

    float    Ik;
    float    Ik_std;
    float    Ik_err;

    float    Vk;
    float    Vk_std;
    float    Vk_err;

    float    Ib;
    float    Ib_std;
    float    Ib_err;

    float    Vb;
    float    Vb_std;
    float    Vb_err;

    float    Vbias_pos;
    float    Vbias_neg;

    uint32_t    aux_pwr1;
    uint32_t    aux_pwr2;
    uint32_t    aux_pwr3;

    uint32_t    ctd;
    uint32_t    optode;
    uint32_t    comm_pwr;

    char        tester[MAX_TESTER_NAME];
    char        firmware_version[MAX_VERSION_SIZE];

};

// systemData struct organized for 4 byte packing, also fixed buffer overruns by setting size of fields in define
struct systemData
{
    //---------------- samplingData ---------------------------
	uint32_t sampling_period;	    //8 pH sampling period
	uint32_t chksum;	    	// was sample_average DEPRECATED (was int32_t) 12 Number of pH sensor samples to average
	uint32_t averaging_interval;    //16 Number of seconds between each average

	float low_batt_volt;            //4  Low battery voltage threshold
	float TCOffset;					//24 DuraFET temperature calibration variable
    float TCSlope;
	float k0ext;					//28 was float Eo_ext_25C;, renamed k0ext 2 Apr 2021
	float k0int;					//32 was float Eo_int_25C;, renamed k0int  2 Apr 2021
    float k2ext;                    //28 added  25 Apr 2021
    float k2int;                    //32 added  25 Apr 2021
    double quadTherm_c0;             // 4 coefficient c0 for thermistor
    double quadTherm_c1;             // 4 coefficient c1 for thermistor
    double quadTherm_c2;             // 4 coefficient c2 for thermistor
    double quadTherm_c3;             // 4 coefficient c3 for thermistor
    double shTherm_A;                // steinhart-hart coefficient A
    double shTherm_B;                // steinhart-hart coefficient C
    double shTherm_C;                // steinhart-hart coefficient B
	float default_sal;              //36 default salinity (FRAM) TODO
	//float spareVar;                 // was sensor_sal
	//float sensor_sal;               // salinity read from conductivity (SBE, Aanderaa)   FRAM

	uint32_t Vrsi_sps;				//Vrsi_sps	//418 pH Vint data rate setting (sps)
	uint32_t Vrsi_trials;           //Vrsi_trials
	uint32_t Vrse_sps;
	uint32_t Vrse_trials;
	uint32_t Vtherm_sps;
	uint32_t Vtherm_trials;
	uint32_t Ik_sps;
	uint32_t Ik_trials;
	uint32_t Vk_sps;
	uint32_t Vk_trials;
	uint32_t Ib_sps;
	uint32_t Ib_trials;
    uint32_t Vb_sps;
    uint32_t Vb_trials;
    uint32_t Vbias_sps;
    uint32_t Vbias_trials;

    uint32_t offset_Ik;             // 800uV or so, tbd measure a QA step.
    uint32_t offset_Ib;
	output_mode output;				//422 Verbose mode during deployment if true (enum is 4 bytes?)
	uint32_t test_mode;		        //426 Indicates test deployment
	uint32_t fast_mode;             // Future: changed to sampling mode (fast, precise, etc.)
	uint32_t solenoid_on2hold_msec;
	uint32_t solenoid_hold_pwm;
	uint32_t solenoid_holdtime;     // new 20 Jul 2021

    uint32_t baud_rate;        //470 baud rate  (added by tm Jul 2018)
	unsigned char data_cfg[MAX_NUMOF_CONFIG_FIELDS];     //data field / logging configuration (added by tm Jul 2018)
	unsigned char app_cfg[MAX_NUMOF_APP_CONFIG_FIELDS];

    bool GMT;                       //456 GMT or Local time
    bool sample_aligned;            //460 Sample aligned to hour

    uint32_t diag;                  // diagnostic flag, for developer
    uint32_t debug_flag;            // turn on diagnostic debug printf's


    // Sampling and Sequencing StateMachine variables
    uint32_t deploy_time;               // timestamp of when 'deploy' menu action.   deployment time  (Todo, put in FRAM?) (variable location changed from above diag).
    uint32_t start_pump_time;         // (seconds) Wakeup on sampling interval, but check the 'start deployment time' before actual pumping/sampling 16 Feb 2022


    uint32_t pump_seq_type;             // 0) legacy single pump, 1) BEAMS v1 dual pump seq, 2) BEAMS v2
    uint32_t sampleCnt_duty_on;         // duty cycle for extending experiment.   3 days on, 5 days off.   Number of 'sample periods' on
    uint32_t sampleCnt_duty_off;        // in sample periods.    Accept input in hours, translate to sample periods (keep implementation simple for now).
    uint32_t pump1_cycles;                   // = 10 cycles
    uint32_t pump2_cycles;                   // = 5 cycles
    uint32_t pump1_ontime;          //20 Active pump time;                 // = 30 cycles
    uint32_t pump2_ontime;                 // = 10 cycles

    uint32_t pump_spare[16];            // make room for other variables (future pump sequencer) pump3, etc.

    // was float spare[9];
    float pHOffset;                 // new 3 Aug 2021 (speculative placeholders, can be used as spare)  k0, etc are used for offsets on ph
    float pHSlope;
    //float TCSlope;
    float sensor_ctd_TC;
    float sensor_optode_TC;
	float spare[64];                // LAYOUT CHANGE 16 Feb 2022, now 64 for v4.x future expansion. was 4 (was 9) 4 byte spares (36 bytes) for future expansion without causing EEPROM struct issues
	//------------------ System MetaData ------------------
	// re-arranged struct to put char fields after numeric
    char fileName[MAX_FILENAME];              //116 The name the user would like to give their data output file, fatfs max is 8.3
    char user[MAX_USER_INITIALS];                  //452 User initials

    char board_SN[MAX_BOARD_SN];              //146 (added 3Apr2021) board (MFET, MpHOx, nanoFET) serial number
    char mcap_SN[MAX_MCAP_SN];               //176 (added 3Apr2021) mcap serial number
    char durafet_SN[MAX_DURAFET_SN];            //226 DuraFET sensor serial number
    char package_name[MAX_PACKAGE_NAME];       //196 Name of integrated package (underway system, etc.)  (was 20, now 30, bug in buff entry size)

    char optode_SN[MAX_OPTODE_SN];             //346 (added 3Apr2021) Aanderaa optode serial number
    char ctd_SN[MAX_CTD_SN];                 //376 (added 3Apr2021) Aanderaa conductivity or MicroCat aka ctd serial number
    char pump_SN[MAX_PUMP_SN];                  //406 Pump serial number
    char board_fab_note[MAX_BOARD_FABNOTE];        //  (added 4Apr2021)  board fabrication notes, dates, etc.
    char deploy_note[MAX_DEPLOY_NOTE];          // (Todo FRAM)

    struct qaData qa;
};


//
struct systemSamplingData
{
    int32_t state;                  //430 IDLE, DEPLOYED, COMMAND,  NOT USER MODIFIABLE                        <<<<<------
    uint32_t nextWakeUp;            //434 Next intended RTC match (wake-up time) NOT USER MODIFIABLE           <<<<<------
    uint32_t next_gdata_fptr;       //438 The file position of the next gdata sample. NOT USER MODIFIABLE      <<<<<------
    uint32_t current_sample;        //442 The current data record to be stored. NOT USER MODIFIABLE            <<<<<------
    float AD24_std;                 //464 standard deviation for AD24                                          <<<<--------
    float sensor_sal;               // salinity read from conductivity (SBE, Aanderaa)
    float spare1;
    float spare2;
    float spare3;
    float spare4;
    uint32_t initNum;
    uint32_t pump_seq_state;      // for controlling/sequencing pump/solenoid
    uint32_t pump1_cnt;
    uint32_t pump2_cnt;
    uint32_t start_pump_cntdown;      // count down in 'sample periods'
};
//#ifdef OLDCODE
// OLD deprecated struct
// variables that change each sample (will wear out onchip 500k write cycle flash / eeprom)
struct systemDataVolatile
{
    uint32_t state;                     // IDLE, DEPLOYED, COMMAND,  NOT USER MODIFIABLE
    uint32_t nextWakeUp;                // Next intended RTC match (wake-up time) NOT USER MODIFIABLE
    uint32_t next_gdata_fptr;           // The file position of the next gdata sample. NOT USER MODIFIABLE Note: was unsigned long
    uint32_t current_sample;            // The current data record to be stored. NOT USER MODIFIABLE
    float AD24_std;
    uint32_t samp_state;
    uint32_t chksum;
};

struct keytapeVars
{
    uint32_t headPtr;
    uint32_t tailPtr;
};


#define SYSDATACHG_NUMWORDS     7       // number of 4byte words in above struct
//#endif



//DEFAULT Configuration for get_sample() is for all fields
// index into sys_data.data_cfg[]
#define CFG_SAMPLE_NUM          0
#define CFG_TIMESTAMP           1   // + MM/DD/YYYY HH:MM:SS

#define CFG_V_THERMISTOR        2       //+ Vthermistor\t
#define CFG_V_THERMISTOR_STD    3   //+ Vthermistor_std\t
#define CFG_CALC_TEMP           4   //+ calculated_temperature_Vthermistor\t

#define CFG_VRSI               5   //+ Vint\t
#define CFG_VRSI_STD           6   //+ Vint_std\t
#define CFG_CALC_PH_VRSI          7   //+ estimated_pH_int\r\n

#define CFG_VRSE               8   //+ Vext
#define CFG_VRSE_STD           9   // + Vext_std
#define CFG_CALC_PH_VRSE          10   //+ estimated_pH_ext\r\n (new 6May2019 TM)

#define CFG_VRSI_BIASED        11   //+ Vint_offset\t
#define CFG_VRSI_BIASED_STD    12   //+ Vint_offset_std\t
#define CFG_VRSE_BIASED        13   //+ Vext_offset\t
#define CFG_VRSE_BIASED_STD    14   //+ Vext_offset_std\t


#define CFG_V_COUNTER_ELECT     15   //+ Vcounter_electrode
#define CFG_V_COUNTER_ELECT_STD 16   //+ Vcounter_electrode_std
#define CFG_I_COUNTER           17   // + Counter_current
#define CFG_I_SUBSTRATE         18   //+ Substrate_current

#define CFG_VIN_BAT_VOLT        19   //+ Battery_Volt
#define CFG_BIAS_BAT_POS        20   //+ Bias Bat Volt
#define CFG_BIAS_BAT_NEG        21

#define CFG_BRD_TEMP        22   //+ Board_Temperature\t
#define CFG_BRD_HUMIDITY        23   // + Humidity_sensor


#define CFG_OPTODE              24   // Aanderaa optode
#define CFG_CTD                 25   // Aanderaa or MicroCat conductivity, AKA CFG_CONDUCTIVITY new 25 Mar 2021

#define CFG_OCR                 26  // was spare1
#define CFG_SPARE2              27

#define CFG_SPARE3              28
#define CFG_SPARE4              29
#define CFG_SPARE5              30
#define CFG_SPARE6              31

// MAX_NUMOF_CONFIG_FIELDS is set to 32 above.

//sys_data.app_cfg
// App config, used for bringing out new features, etc
#define APPCFG_SAMPLING_DIAG    0   // switch on timing printfs in fast_sample
#define APPCFG_TEMPC_SH_ALG     1   // used in Durafet_temp to switch algorithm
#define APPCFG_MICROSD_ENABLE   2   // APPCFG_SAMP_FLEX        2   // In fast_sample, used to allow for user edit variables for Trials and sps per ADS1284 sample
#define APPCFG_MENU_LEVEL       3
#define APPCFG_DEPLOY_UARTECHO  4   //Turn off uartEcho in deployment to help m2m with labview   //#define APPCFG_SPARE4           4
#define APPCFG_EXEC_SWITCHERONI 5   // Was APPCFG_SPARE5
#define APPCFG_SPARE6           6
#define APPCFG_SPARE7           7
#define APPCFG_SPARE8           8
#define APPCFG_SPARE9           9
#define APPCFG_SPARE10          10
#define APPCFG_SPARE11          11
#define APPCFG_SPARE12          12
#define APPCFG_SPARE13          13
#define APPCFG_SPARE14          14
#define APPCFG_SPARE15          15






//----------- Key Defs --------
#define CTRL_X          24
//#define CTRL-X          CTRL_X


// Global variables
extern struct systemData sys_data;
extern struct systemDataVolatile sys_data_vol;
extern struct systemDataVolatile sys_data_chg;

void read_bias_bat(void);

void display_battery_boardSensors(void);
void display_ph_ref_therm_volts(void);
void display_calcd_pH_intRef_therm(void);
void display_calcd_pH_extRef_therm_sal(float Salinity);
void communicate_with_instruments(void);
int power_output_tests(void);
void test_24bit_adc_mux(void);
int board_qa_and_init(int initFlg);


void initSysDataVolatileVariables(void);

void SysTickHandler(void);
unsigned long Timer_10ms(bool reset);
unsigned long Timer_1ms(bool reset);
void ms_delay(unsigned int msec);
void delay_msec(unsigned int msec);
struct tm *get_RTC_time(void);

uint32_t storeSysDataVariables(void); //EEPROM
void retrieveSysDataVariables();
uint32_t smartStoreSysData(void);
void storeSysSampFRAMVariables(void);
void retrieveSysSampFRAMVariables(void);
void initSysSampFRAMVariables(void);

int isNameInSavedDataString(char* name);
void saveSysDataVariableName();

float batt_volt();
float batt_volt_iso();


float controller_temp();
float pressure(void);
//int writeDeploymentInformationHeader(const time_t currentTime);  //deprecated 21 Apr 2021

void sendlast_takesample(void);
//void fast_sample(int txFlg);  // moved to sampling.c

void error_store(const char *error_buff);
float DuraFET_temp(float V_therm, float TCOffset);
float calc_pHext(float Eext, float TC, float salt);
float calc_pHint(float Eint, float TC);
void ph_calib(void);

float read_env_sensors(void);




#endif /* MPHOX_SYSTEM_H_ */
