/*
 * adv.h
 * Library for interface with Nortek Vector ADV
 *
 *  Created on: Oct 4, 2021
 *      Author: Irene Hu
 *
 *  Based on MIT code - removes synch pin, recorder functions
 */

#ifndef ADV_H_
#define ADV_H_

#define PRINT_ADV_TIMING // print out some timing info
// moved here from adv.c so can be used in EC functions


// #includes initially copied from optode - annotated/added as i discovered what they're for
// not sure why optode doesn't include its uart, so added that
#include "system.h" // timers - also includes time.h
#include "uart2.h" // uart driver for rs232 comms
#include "uartstdio.h" // UARTwrite etc for test menu and writing buffer to screen
#include "user_io.h" // uprintf, getUserInput
#include "fatfs/src/ff.h" // output to file
#include "microsd.h" // some more file output stuff
#include "stdint.h" // not sure where system.c, sample.c, etc are getting the defs for uintxx; do it explicitly here
#include "sleep.h" // adv_comm menu sleeps if doesn't receive input

#define ADV_BAUD 115200

#define ACK_TIMEOUT_MS 1500 // amount of time to wait for an Ack or Nack
#define CMD_TIMEOUT_MS 5000 // WiringSerial used to block for up to 10s waiting for a byte on the port

#define VEL_READ_TIME_BUFFER_US 1000 // time before next sync pulse to start reading and outputting velocity and system data

#define ADV_ACK 0x06
#define ADV_NACK 0x15
#define ADV_SYNCBYTE 0xa5
#define ADV_IDSYS 0x11
#define ADV_IDVEL 0x10
#define ADV_IDHDR 0x12
#define ADV_IDPCK 0x07

#define SNR_SCALE 0.55 // scale factor for calculating SNR (dB/counts)
// 5/20/22 Evan claims is 0.55 for all Vectors

#define PCHK_NUMSAMPLES 300 // number of samples in a probe check for Vector
#define NUMBEAMS 3

#define ADV_CHECKSUM_BASE 0xb58c
//#define ADV_CHECKSUM_FAT 0x21b7 // no fat anymore...

// 6 byte clock data in BCD format
struct adv_clock {
    unsigned char cSecond;
    unsigned char cMinute;
    unsigned char cHour;
    unsigned char cDay;
    unsigned char cMonth;
    unsigned char cYear;
};


// deployment config structure (only relevant fields)
struct adv_userConfig {
    uint16_t T1; //transmit pulse length (counts)
    uint16_t T2; //blanking distance (counts)
    uint16_t T3; //receive length (counts)
    uint16_t T4; //time between pings (counts)
    uint16_t T5; //time between burst sequences (counts)
    uint16_t NPings; //number of beam sequences per burst
    uint16_t AvgInterval; //512/Sampling Rate
    uint16_t NBeams; //number of beams
    uint16_t TimCtrlReg; //timing controller mode
    uint16_t CompassUpdRate; //compass update rate
    uint16_t CoordSystem; //coordinate system (ENU, XYZ or BEAM)
    uint16_t NBins; //number of cells
    uint16_t BinLength; //cell size
    uint16_t MeasInterval; //measurement interval
    char DeployName[6]; //recorder deployment name
    uint16_t WrapMode; //recorder wrap mode
    struct adv_clock clockDeploy; //deployment start time (BCD)
    uint32_t DiagInterval; //number of seconds between diagnostics measurements
    uint16_t Mode; //mode
    uint16_t AdjSoundSpeed; //user input sound speed adjustment factor
    uint16_t NSampDiag; //# samples in diagnostics mode
    uint16_t NBeamsCellDiag; //# beams/cell number to measure in diagnostics mode
    uint16_t NPingsDiag; //# pings in diagnostics/wave mode
    uint16_t ModeTest; //mode test
    uint16_t AnaInAddr; //analog input address
    uint16_t SWVersion; //software version
    char VelAdjTable[180]; //velocity adjustment table- no idea what this is either
    char Comments[180]; //file comments
    //the next few might be AWAC stuff or something, not sure
    //uint16_t Mode_2;
    //uint16_t DynPercPos;
    //uint16_t T1_2;
    //uint16_t T2_2;
    //uint16_t T3_2;
    //uint16_t NSamp_2;
    uint16_t B1; //number of samples per burst
    uint16_t AnaOutScale; //analog output scale factor (16384 = 1.0, max = 4.0);
    uint16_t CorrThresh; //correlation threshold for resolving ambituities
    uint16_t TiLag2; //transmit pulse length (counts) second lag
    int8_t checksumFlag; //0 for succeed, 1 for fail
};


// Vector header data
struct adv_dataHeader {
    struct adv_clock timestamp;
    uint16_t NRecords; //number of velocity samples to follow
    uint8_t Noise[NUMBEAMS+1]; //noise amplitude beams 1, 2, 3 (counts) + spare byte
    uint8_t Correlation[NUMBEAMS+1]; //noise correlation beams 1, 2, 3 + spare byte
    int8_t checksumFlag; //0 for succeed, 1 for fail
};

// Vector probe check data
struct adv_probeChkData {
    uint16_t Samples; //number of samples per beam
    uint16_t FirstSample; //first sample number
    uint8_t Amp[NUMBEAMS][PCHK_NUMSAMPLES]; //amplitude [beam#][sample#]
    int8_t checksumFlag; //0 for succeed, 1 for fail
};

// Vector velocity data
struct adv_velocityData {
    uint8_t AnaIn2LSB; //analog input 2 LSB
    uint8_t Count; //ensemble counter
    uint8_t PressureMSB; //pressure MSB
    uint8_t AnaIn2MSB; //analog input 2 MSB
    uint16_t PressureLSW; //pressure LSB (dBar)
    uint16_t AnaIn1; //analog input 1
    int16_t Vel[NUMBEAMS]; //velocity beam 1/X/E, 2/Y/N, 3/Z/U (mm/s)
    uint8_t Amp[NUMBEAMS]; //amplitude beam 1, 2, 3 (counts)
    uint8_t Corr[NUMBEAMS]; //corr beam 1, 2, 3 (%)
    int8_t checksumFlag; //0 for succeed, 1 for fail
};

// Vector system data
struct adv_sysData {
    struct adv_clock timestamp;
    uint16_t Battery; //battery voltage (0.1 V)
    uint16_t SoundSpeed; //speed of sound (0.1 m/s)
    int16_t Heading; //compas heading (0.1 deg)
    int16_t Pitch; //compass pitch (0.1 deg)
    int16_t Roll; //compass roll (0.1 deg)
    int16_t Temperature; //temperature (0.01 deg C)
    char Error; //error code
    char Status; //status code
    uint16_t AnaIn; //analog input
    int8_t checksumFlag; //0 for succeed, 1 for fail
};


// initialize and uart wrapper functions
void adv_init(void);
int adv_open(void);
int adv_rxBytesAvail(void);
unsigned char _adv_getc(void);
void _adv_putc(unsigned char c);
void _adv_flushRx(void);
void _adv_flushTx(bool bDiscard);
int _adv_write(const char *pcBuf, uint32_t ui32Len);

// workhorse functions
void adv_comm_test(void);
int adv_measure(double measDuration_min, char* fn_append);

// functions involving controller commands only
int adv_flushPort();
void adv_sendBreak();
int adv_powerDown();
int adv_getBatt(unsigned int *battV);
int adv_getMode(char *response, int *mode);
int adv_exitMeasMode();
int adv_exitMeasModeNoNarration();
int adv_getCurrClock(struct adv_clock *clockStruct);
int adv_getUserConfig();
int adv_getDatHeader(struct adv_dataHeader *datHdrStruct);
int adv_getProbeChkDat(struct adv_probeChkData *prbChkStruct);
int adv_getVelData(struct adv_velocityData *velDatStruct, int16_t checkSum);
int adv_getSysData(struct adv_sysData *sysDatStruct, int16_t checkSum);

// other functions
int adv_convertClock(const struct adv_clock *clock, time_t *clockTime);
int adv_printClock(const struct adv_clock *clock, FIL* ofs);
int adv_printUserConfig(FIL* ofs, int txFlg);
int adv_printDatHeader(struct adv_dataHeader *datHdrStruct, FIL* ofs);
int adv_printProbeChkDat(struct adv_probeChkData *prbChkStruct, FIL* ofs);
int adv_printVelDataHdr(FIL* ofs);
//int adv_printVelData(struct adv_velocityData *velDatStruct, FIL* ofs);
int adv_printVelData(struct adv_velocityData *velDatStruct, FIL* ofs, int counter);
int adv_printVelDataHdr_wSNR(FIL* ofs);
//int adv_printVelData_wSNR(struct adv_velocityData *velDatStruct, struct adv_dataHeader *datHdrStruct, FIL* ofs);
int adv_printVelData_wSNR(struct adv_velocityData *velDatStruct, struct adv_dataHeader *datHdrStruct, FIL* ofs, int counter);
int adv_printSysDataHdr(FIL* ofs);
int adv_printSysData(struct adv_sysData *sysDatStruct, FIL* ofs);

// formerly private functions
// private variables
// struct userConfig _config;

int _adv_sendTwoCharCmd(char *cmdToADV);
int _adv_receiveAck();
int16_t _adv_twoBytes_to_int(unsigned char byte1, unsigned char byte2);
int16_t _adv_getTwoBytes();
int _adv_sortIncomingDataStruct(int16_t *checkSum);
unsigned char _adv_BCDToChar(unsigned char cBCD);
int _adv_clockBytesToStruct(char *clockByteStream, struct adv_clock *clockStruct);

// these variables moved here from adv.c so can access in EC functions
struct adv_userConfig _adv_config; // will remain unchanged, so make it a fixed variable
// just need to call fxn to read it once, and then it will always be there
// no private class variables but we'll keep this as a system variable, since it gets randomly used by some adv functions and doesn't change
int adv_validUserConfig; // 1 if it's valid, 0 if not


#endif /* ADV_H_ */
