/*
 * David Muller; Germán Alfaro
 * davehmuller@gmail.com; alfaro.germanevera@gmail.com
 *
 * Thom Maughan; tm@mbari.org  2018...
 */


#ifndef SEAPHOX_MFET_SYSTEM_H_
#define SEAPHOX_MFET_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>


#include "inc/tm4c123gh6pge.h"
#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"



#if BOARD_MFET == 1
#define 	VERSION		"v3.3.1 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     "v3.3.1 MFET v2"     // 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  1
#endif
#if BOARD_SEAPHOX==1
#define     VERSION     "v3.3.1 SEAPHOX"   // SEAPHOX software version
// no battery backed hib
#define NONVOLATILEMEM  "Nonvol mem: Onchip 500K cycle endurance EEPROM"
#define EEPROM_REG_STORE 1      // old, wear out EEPROM
#define HIB_REG_STORE   0       // used to turn on HIB register store to prevent EEPROM wearout
#define FRAM_REG_STORE  0
#endif
#ifndef VERSION
#define     VERSION     "COMPILER FLAGS BOARD_MFET or BOARD_SEAPHOX NOT DEFINED"
#endif

#define NOMINAL_SAMPLE_TIMES    1
#define FAST_SAMPLE_TIMES       0

#if NOMINAL_SAMPLE_TIMES==1

#endif

#if FAST_SAMPLE_TIMES==1


#endif

/* 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
#define OPTODE_BUFFER_SIZE 		128
#define AUX1_BUFFER_SIZE		128
#define AUX2_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
#define TWOTOTHE23 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

/*
 * 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     30
struct systemData
{
	float low_batt_volt;	        // Low battery voltage threshold
	uint32_t sampling_period;	    // pH sampling period
	int32_t sample_average;	    	// Number of pH sensor samples to average
	uint32_t averaging_interval;    // Number of seconds between each average
	uint32_t pumpon_time;		    // Active pump time
	float TCOffset;					// DuraFET temperature calibration variable
	float Eo_ext_25C;
	float Eo_int_25C;
	float default_sal;
	char fileName[80];    			// The name the user would like to give their data output file
	char sensor_name[20];           // Temperature sensor name
	char durafet_SN[30];			// DuraFET sensor serial number
	char capadap_SN[30];			// CAP adapter serial number
	char ISE_SN[30];				// ISE serial number
	char microcat_SN[30];			// Microcat serial number
	char pump_SN[30];				// Pump serial number
	int press_full_scale;			// Pressure sensor full-scale value (psi)
	int Vint_gain;					// pH Vint PGA gain setting
	int Vint_sps;					// pH Vint data rate setting (sps)
	output_mode output;				// Verbose mode during deployment if true
	int test_mode;					// Indicates test deployment
//#if BOARD_SEAPHOX==1
	int state;						// IDLE, DEPLOYED, COMMAND,  NOT USER MODIFIABLE                        <<<<<------
	uint32_t nextWakeUp;			// Next intended RTC match (wake-up time) NOT USER MODIFIABLE           <<<<<------
	unsigned long next_gdata_fptr;	// The file position of the next gdata sample. NOT USER MODIFIABLE      <<<<<------
	unsigned int current_sample;	// The current data record to be stored. NOT USER MODIFIABLE            <<<<<------
//#endif
//#if BOARD_MFET==2
//    int state_PLACEHOLDER;                      // IDLE, DEPLOYED, COMMAND,  NOT USER MODIFIABLE                        <<<<<------
//    uint32_t nextWakeUp_PLACEHOLDER;            // Next intended RTC match (wake-up time) NOT USER MODIFIABLE           <<<<<------
//    unsigned long next_gdata_fptr_PLACEHOLDER;  // The file position of the next gdata sample. NOT USER MODIFIABLE      <<<<<------
//    unsigned int current_sample_PLACEHOLDER;    // The current data record to be stored. NOT USER MODIFIABLE            <<<<<------
//#endif


	char user[10];					// User initials
	bool GMT;						// GMT or Local time
	bool sample_aligned;			// Sample aligned to hour
//#if BOARD_SEAPHOX==1
	float AD24_std;					// standard deviation for AD24                                          <<<<--------
//#endif
//#if BOARD_MFET==2
//    float AD24_std_PLACEHOLDER;                 // standard deviation for AD24
//#endif
	unsigned long baud_rate;        // 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 fast_mode;        // added 10 Jun 2019
};

// 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;
};
#define SYSDATACHG_NUMWORDS     7       // number of 4byte words in above struct

//DEFAULT Configuration for get_sample() is for all fields
// index into sys_data.data_cfg[]
#define CFG_SAMPLE_NUM          0
#define CFG_TIMEDATE            1   // + MM/DD/YYYY HH:MM:SS
#define CFG_ENV_BAT_VOLT        2   //+ Battery_Volt
#define CFG_ENV_BRD_TEMP        3   //+ Board_Temperature\t
#define CFG_ENV_HUMIDITY        4   // + Humidity_sensor
#define CFG_INT_PRESSURE        5   //+ Internal_pressure
#define CFG_V_THERMISTOR        6       //+ Vthermistor\t
#define CFG_V_THERMISTOR_STD    7   //+ Vthermistor_std\t
#define CFG_V_INT_OFFSET        8   //+ Vint_offset\t
#define CFG_V_INT_OFFSET_STD    9   //+ Vint_offset_std\t
#define CFG_V_EXT_OFFSET        10   //+ Vext_offset\t
#define CFG_V_EXT_OFFSET_STD    11   //+ Vext_offset_std\t

#define CFG_V_INT               12   //+ Vint\t
#define CFG_V_INT_STD           13   //+ Vint_std\t
#define CFG_V_EXT               14   //+ Vext
#define CFG_V_EXT_STD           15   // + Vext_std
#define CFG_V_COUNTER_ELECT     16   //+ Vcounter_electrode
#define CFG_V_COUNTER_ELECT_STD 17   //+ Vcounter_electrode_std
#define CFG_I_COUNTER           18   // + Counter_current
#define CFG_I_SUBSTRATE         19   //+ Substrate_current
#define CFG_CALC_TEMP           20   //+ calculated_temperature_Vthermistor\t
#define CFG_EST_PH_INT          21   //+ estimated_pH_int\r\n
#define CFG_EST_PH_EXT          22   //+ estimated_pH_ext\r\n (new 6May2019 TM)
#define CFG_OPTODE              23

#define DATA_CFG_NUM    24          // Number of Data Config items (used in main.c for array index limit)


// Global variables
extern struct systemData sys_data;
extern struct systemDataVolatile sys_data_vol;
extern struct systemDataVolatile sys_data_chg;
extern char MicroCAT_buff[MICROCAT_BUFFER_SIZE];
extern char Optode_buff[OPTODE_BUFFER_SIZE];

// Function Macros
#define pump_on()		ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, 0xff);
#define pump_off()		ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, 0x00);
#define pressureOn()	ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_5, 0xff);
#define pressureOff()	ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_5, 0x00);
//#define console_on()	ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0xff);
// Thom new - make console into a routine
//#define console_off()	ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0x00);

// Function prototypes for System.c
void print_header(void);

void console_on(void);
void console_off(void);

void initSysDataVolatileVariables(void);

void SysTickHandler(void);
unsigned long Timer_10ms(bool reset);
void retrieveSysDataVariables();
uint32_t smartStoreSysData(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, const time_t firstSample, int txFlg);

void sendlast_takesample(void);
void get_sample(int txFlg);
void fast_sample(int txFlg);

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);

void led_green_off(void);
void led_green_on(void);
void led_green_toggle(void);
void led_red_off(void);
void led_red_on(void);
void led_red_toggle(void);

void profile_toggle(int target);
void profile_off(int target);
void profile_on(int target);

#endif /* SEAPHOX_MFET_SYSTEM_H_ */
