/***************************************************************************//**
 * @file
 * @brief Driver for Si117x
 * @version 0.0.1
 *******************************************************************************
 * @section License
 * <b>Copyright 2017 Silicon Labs, Inc. http://www.silabs.com</b>
 *******************************************************************************
 *
 * This file is licensed under the Silabs License Agreement. See the file
 * "Silabs_License_Agreement.txt" for details. Before using this software for
 * any purpose, you must agree to the terms of that agreement.
 *
 ******************************************************************************/

#ifndef SI117x_DRIVER_H
#define SI117x_DRIVER_H
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)     //if C99 or later (https://sourceforge.net/p/predef/wiki/Standards/)
    #define bool char	//Workaround for VC2010 (VC2010 doesn't have stdbool.h as it doesn't support the C99-standard "bool").
    #define false 0
    #define true  1
#else
    #include <stdbool.h>
#endif

#include "si117xdrv_config.h"
#include "si117x_functions.h"

typedef int32_t Si117x_Ecode_t; ///< SI117XDRV error code

#define ECODE_SI117XDRV_OK                0 ///< Success return value.
#define ECODE_SI117XDRV_QUEUE_FULL       -1 ///< Fifo queue full.
#define ECODE_SI117XDRV_QUEUE_EMPTY      -2 ///< Fifo queue empty.
#define ECODE_SI117XDRV_ALL_QUEUES_USED  -3 ///< No more queues left.
#define ECODE_SI117XDRV_PARAM_ERROR      -4 ///< Invalid parameter.
#define ECODE_SI117XDRV_QUEUE_SIZE_ERROR -5 ///< Invalid queue size.
#define ECODE_SI117XDRV_RUNNING          -6 ///< Si117x is already running.
#define ECODE_SI117XDRV_NOT_RUNNING      -7 ///< Si117x is not running.
#define ECODE_SI117XDRV_ALL_CB_USED      -8 ///< All callbacks used.
#define ECODE_SI117XDRV_UNINITIALIZED    -9 ///< All callbacks used.

#ifndef NULL
#define NULL 0
#endif
//typedef void* HANDLE;

#define SI117XDRV_UNINITIALIZED_QUEUE_ID 0xffff ///< Invalid queue ID for init code

///PPG sample data typedef
typedef struct {
  uint16_t sequence;    ///< irq sequence number
  uint16_t timestamp;   ///< irq timestamp
  uint8_t syncMessage; ///< sync message received
  int32_t ppg1;        ///< ppg1 sample data
  int32_t ppg2;        ///< ppg2 sample data
  int32_t ppg3;        ///< ppg3 sample data
  int32_t ppg4;        ///< ppg4 sample data
} SI117XDRV_PPG24bSample_t;

#define SI117XDRV_PPG_24BIT_SAMPLE_SIZE_BYTES 21 ///< PPG sample size in bytes

///PPG 16bit sample data typedef. Use this data type to save memory.
typedef struct {
  uint16_t sequence;    ///< irq sequence number
  uint16_t timestamp;   ///< irq timestamp
  uint8_t syncMessage; ///< sync message received
  int16_t ppg1;        ///< ppg1 sample data
  int16_t ppg2;        ///< ppg2 sample data
  int16_t ppg3;        ///< ppg3 sample data
  int16_t ppg4;        ///< ppg4 sample data
} SI117XDRV_PPGSample_t;

#define SI117XDRV_PPG_SAMPLE_SIZE_BYTES 13 ///< PPG 16 bit sample size in bytes

///ECG sample data typedef
typedef struct {
  uint16_t sequence;   ///< irq sequence number
  uint16_t timestamp;  ///< irq timestamp
  uint8_t syncMessage;///< sync message received
  int32_t ecg;        ///< ecg sample data
} SI117XDRV_ECGSample_t;

#define SI117XDRV_ECG_SAMPLE_SIZE_BYTES 9 ///< ECG sample size in bytes

///ECG sample data typedef
typedef struct {
  uint16_t sequence;   ///< irq sequence number
  uint16_t timestamp;  ///< irq timestamp
  uint8_t syncMessage;///< sync message received
  uint8_t  data[4];    ///< ecg ld sample data
} SI117XDRV_ECGLDSample_t;

#define SI117XDRV_ECG_LD_SAMPLE_SIZE_BYTES 9 ///< ECG LD sample size in bytes

///bioz sample data typedef
typedef struct {
  uint16_t sequence;   ///< irq sequence number
  uint16_t timestamp;  ///< irq timestamp
  uint8_t syncMessage;///< sync message received
  int32_t bioz;       ///< bioz sample data
} SI117XDRV_BIOZSample_t;

#define SI117XDRV_BIOZ_SAMPLE_SIZE_BYTES 9 ///< BIOZ sample size in bytes

///Sample size settings
typedef enum {
	sample16bit = 0, ///< 16 bit data
	sample24bit = 1  ///< 24 bit data
} SI117XDRV_SampleSize_t;

///Sync configuration settings
typedef enum {
	SynchModeNone         = 0, ///< None
	SynchModeAccel        = 1, ///< Accelerometer
	SynchModeTriggerIn    = 2, ///< Trigger in
	SynchModeTriggerOut   = 3, ///< Trigger out
	SynchModeSi117xMaster = 4, ///< master
	SynchModeSi117xSlave  = 5  ///< slave
} SI117XDRV_SynchMode_t;

///MS pin polarity setting
typedef enum {
	MSPolarHighLowHigh    = 0, ///< high-low-high
	MSPolarLowHighLow     = 1  ///< low-high-low
} SI117XDRV_MSPolar_t;

#define SI117XDRV_TASK_PPG1_EN     (1<<0) ///< PPG1 task enable bit
#define SI117XDRV_TASK_PPG2_EN     (1<<1) ///< PPG2 task enable bit
#define SI117XDRV_TASK_PPG3_EN     (1<<2) ///< PPG3 task enable bit
#define SI117XDRV_TASK_PPG4_EN     (1<<3) ///< PPG4 task enable bit
#define SI117XDRV_TASK_BIOZ1_AC_EN (1<<4) ///< BIOZ AC task enable bit
#define SI117XDRV_TASK_BIOZ_DC_EN  (1<<5) ///< BIOZ DC task enable bit
#define SI117XDRV_TASK_ECG_EN      (1<<6) ///< ECG task enable bit
#define SI117XDRV_TASK_ECG_LD_EN   (1<<7) ///< ECG LD task enable bit

#define SI117XDRV_IRQ_EN_FIFO      (1<<0) ///< Fifo irq enable bit
#define SI117XDRV_IRQ_EN_PPG1      (1<<1) ///< Legacy PPG irq enable bit
#define SI117XDRV_IRQ_EN_WD        (1<<2) ///< Wrist detect irq enable bit
#define SI117XDRV_IRQ_EN_LD        (1<<3) ///< Lead detect irq enable bit

///Si117x global configuration
typedef struct {
	uint32_t ppgSampleRateus;       ///< desired PPG sample rate in us
	uint32_t ecgSampleRateus;       ///< desired ECG sample rate in us
	uint32_t ecgldSampleRateus;     ///< desired ECG LD sample rate us
	uint32_t biozSampleRateus;      ///< desired bioz sample rate in us
	uint32_t accelSyncRateus;       ///< accel synchronization period in us
	uint16_t fifo_int_level;        ///< fifo interrupt level
	uint8_t  taskEnable;            ///< task enable
	bool     fifo_self_test;        ///< enable fifo self test mode
	bool     fifo_disable;          ///< disable fifo
	SI117XDRV_SynchMode_t  synch_mode;   ///< sync mode
	SI117XDRV_MSPolar_t    ms_polar;     ///< ms pin polarity
	SI117XDRV_SampleSize_t ppgSampleSize;///< ppg sample size setting
	SI117XDRV_SampleSize_t ecgSampleSize;///< ecg sample size setting
	SI117XDRV_SampleSize_t biozSampleSize;///< bioz sample size setting
	uint8_t ppg_sw_avg; ///< ppg sw avg setting
	uint8_t irq_enable; ///< irq enable setting
}SI117XDRV_GlobalCfg_t;

///Si117x default global configuration
#define SI117XDRV_DEFAULT_GLOBAL_CFG     \
		{   5000 ,                       \
		    5000,                        \
		    0,                           \
		    0,                           \
			0,                           \
		    128,                         \
		    0,                           \
		    false,                       \
		    false,                       \
		    SynchModeNone,               \
			MSPolarHighLowHigh,          \
			sample16bit,                 \
			sample24bit,                 \
			sample16bit,                 \
			0,                           \
            0                            \
		  }

///Si117XDRV ECG configuration
typedef struct {
	uint8_t ecg_measconfig;
	uint8_t ecg_adcconfig;
	uint8_t ecg_feconfig;
} SI117XDRV_ECGCfg_t;

///Si117XDRV ECG LD configuration
typedef struct {
	uint8_t ecg_threshold;
	uint8_t ecg_ldconfig;
	uint8_t ecg_ld_freq_sel;
} SI117XDRV_ECGLDCfg_t;

///Si117x default ecg configuration
#define SI117XDRV_DEFAULT_ECG_CFG       \
		{   0 ,                         \
		    0x8,                        \
		    0,                          \
		}

///Si117x default ecg ld configuration
#define SI117XDRV_DEFAULT_ECG_LD_CFG    \
		{   0 ,                         \
		    0,                          \
		    0,                          \
		}

///Si117XDRV one PPG channel configuration
typedef struct
{
  uint8_t ppg_led1_config;
  uint8_t ppg_led2_config;
  uint8_t ppg_led3_config;
  uint8_t ppg_led4_config;
  uint8_t ppg_mode;
  uint8_t ppg_measconfig;
  uint8_t ppg_adcconfig;
} SI117XDRV_PPGChannelCfg_t;

///Si117x default one channel ppg configuration
#define SI117XDRV_DEFAULT_PPG_CHANNEL_CFG     \
		{   0 ,                               \
		    0,                                \
		    0,                                \
		    0,                                \
		    0xf,                              \
		    0x3,                              \
		    0x30,                             \
		  }

///Si117XDRV PPG configuration
typedef struct
{
  uint8_t ppg4_threshold;
  SI117XDRV_PPGChannelCfg_t ppgCfg[4];
} SI117XDRV_PPGCfg_t;

///Si117x default ppg configuration
#define SI117XDRV_DEFAULT_PPG_CFG               \
		{   0 ,                                 \
	        {SI117XDRV_DEFAULT_PPG_CHANNEL_CFG, \
             SI117XDRV_DEFAULT_PPG_CHANNEL_CFG, \
             SI117XDRV_DEFAULT_PPG_CHANNEL_CFG, \
			 SI117XDRV_DEFAULT_PPG_CHANNEL_CFG} \
		}

/// @brief Queue ID.
typedef uint32_t SI117XDRV_DataQueueID_t;


/// @brief Device ID.
typedef uint32_t SI117XDRV_DeviceSelect_t;
/***************************************************************************//**
 * @brief
 *  Typedef for the user supplied callback function which is called when
 *  a specific event happens.
 *
 * @param[in] device
 *   The device.
 *
 * @param[in] user
 *   Extra parameter for user application.
 ******************************************************************************/
typedef void (*SI117XDRV_Callback_t)(SI117XDRV_DeviceSelect_t device, void *user);

/***************************************************************************//**
 * @brief
 *  Typedef for accel sync DLE message received event.
 *
 * @details
 *  The callback function is called when a accel sync DLE message is received
 *  in the fifo data.
 *
 * @param[in] device
 *   The device
 *
 * @param[in] ppgCount
 *   Number of ppg samples received since last DLE message
 *
 * @param[in] user
 *   Extra parameter for user application
 ******************************************************************************/
typedef void (*SI117XDRV_AccelCallback_t)(SI117XDRV_DeviceSelect_t device, uint16_t ppgCount, void *user);

Si117x_Ecode_t SI117XDRV_LeadDetection (SI117XDRV_DeviceSelect_t device, bool *leadDetectStatus);
Si117x_Ecode_t SI117XDRV_WristDetection (SI117XDRV_DeviceSelect_t device, bool *wristDetectStatus);
Si117x_Ecode_t SI117XDRV_ClearWristDetection (SI117XDRV_DeviceSelect_t device);

/***************************************************************************//**
 * Data Fifo Queue Functions
 ******************************************************************************/
Si117x_Ecode_t SI117XDRV_Allocate24bPPGDataQueue(SI117XDRV_DataQueueID_t *id, SI117XDRV_PPG24bSample_t *queueBuffer, int16_t queueSizeInBytes);
Si117x_Ecode_t SI117XDRV_AllocatePPGDataQueue(SI117XDRV_DataQueueID_t *id, SI117XDRV_PPGSample_t *queueBuffer, int16_t queueSizeInBytes);
Si117x_Ecode_t SI117XDRV_AllocateECGDataQueue(SI117XDRV_DataQueueID_t *id, SI117XDRV_ECGSample_t *queueBuffer, int16_t queueSizeInBytes);
Si117x_Ecode_t SI117XDRV_AllocateECGLDDataQueue(SI117XDRV_DataQueueID_t *id, SI117XDRV_ECGLDSample_t *queueBuffer,  int16_t queueSizeInBytes);

Si117x_Ecode_t SI117XDRV_FreeDataQueue(SI117XDRV_DataQueueID_t id);

Si117x_Ecode_t SI117XDRV_ClearQueue (SI117XDRV_DataQueueID_t id);

uint16_t SI117XDRV_NumSamplesInQueue (SI117XDRV_DataQueueID_t id);

Si117x_Ecode_t SI117XDRV_Dequeue24bPPGSampleData (SI117XDRV_DataQueueID_t id, SI117XDRV_PPG24bSample_t *sample);

Si117x_Ecode_t SI117XDRV_DequeueECGSampleData (SI117XDRV_DataQueueID_t id, SI117XDRV_ECGSample_t *sample);

Si117x_Ecode_t SI117XDRV_DequeueECGLDSampleData (SI117XDRV_DataQueueID_t id, SI117XDRV_ECGLDSample_t *sample);

Si117x_Ecode_t SI117XDRV_DequeuePPGSampleData (SI117XDRV_DataQueueID_t id, SI117XDRV_PPGSample_t *sample);



/***************************************************************************//**
 * Device control functions
 ******************************************************************************/
Si117x_Ecode_t SI117XDRV_StartLegacyPPG (SI117XDRV_DeviceSelect_t device, uint8_t ppg_meascount, uint16_t measrate) ;  //used with HRM algorithm (required for DC sense)
Si117x_Ecode_t SI117XDRV_StopLegacyPPG (SI117XDRV_DeviceSelect_t device); //restore previous state
Si117x_Ecode_t SI117XDRV_Stop (SI117XDRV_DeviceSelect_t device);
Si117x_Ecode_t SI117XDRV_Start (SI117XDRV_DeviceSelect_t device);
Si117x_Ecode_t SI117XDRV_SetPPGTaskEnable (SI117XDRV_DeviceSelect_t device, uint8_t ppgTasks); //returns an error if device is currently running
Si117x_Ecode_t SI117XDRV_SetECGTaskEnable (SI117XDRV_DeviceSelect_t device, uint8_t ecgTask);
Si117x_Ecode_t SI117XDRV_FifoFlush (SI117XDRV_DeviceSelect_t device);
/***************************************************************************//**
 * Low level control functions - use these to allow driver to keep track
 * of current config.
 ******************************************************************************/

/***************************************************************************//**
 * Device configuration functions
 ******************************************************************************/
Si117x_Ecode_t SI117XDRV_GetPartInfo (SI117XDRV_DeviceSelect_t device, uint8_t *id, uint8_t *rev, uint8_t *mfr_id, uint8_t *pkg_led_cfg);
Si117x_Ecode_t SI117XDRV_GetFifoIntLevel (SI117XDRV_DeviceSelect_t device, uint16_t *fifo_int_level);
Si117x_Ecode_t SI117XDRV_InitECG (SI117XDRV_DeviceSelect_t device, SI117XDRV_ECGCfg_t *ecgCfg);
Si117x_Ecode_t SI117XDRV_InitECGLD (SI117XDRV_DeviceSelect_t device, SI117XDRV_ECGLDCfg_t *ecgldCfg);
Si117x_Ecode_t SI117XDRV_InitPPG (SI117XDRV_DeviceSelect_t device, SI117XDRV_PPGCfg_t *ppgCfg);
Si117x_Ecode_t SI117XDRV_InitGlobal (SI117XDRV_DeviceSelect_t device, SI117XDRV_GlobalCfg_t *globalCfg);
Si117x_Ecode_t SI117XDRV_Reset (SI117XDRV_DeviceSelect_t device);
Si117x_Ecode_t SI117XDRV_WDIntConfig (SI117XDRV_DeviceSelect_t device, bool enable);
Si117x_Ecode_t SI117XDRV_FifoIntConfig (SI117XDRV_DeviceSelect_t device, bool enable);
Si117x_Ecode_t SI117XDRV_PPG1IntConfig (SI117XDRV_DeviceSelect_t device, bool enable);
Si117x_Ecode_t SI117XDRV_LDIntConfig (SI117XDRV_DeviceSelect_t device, bool enable);
/***************************************************************************//**
 * API configuration functions
 ******************************************************************************/
Si117x_Ecode_t SI117XDRV_RegisterPreStartCallback (SI117XDRV_DeviceSelect_t device, SI117XDRV_Callback_t callback, void *user);
Si117x_Ecode_t SI117XDRV_RegisterAccelSyncCallback (SI117XDRV_DeviceSelect_t device, SI117XDRV_AccelCallback_t callback, void *user);
Si117x_Ecode_t SI117XDRV_RegisterPostStartCallback (SI117XDRV_DeviceSelect_t device, SI117XDRV_Callback_t callback, void *user);
Si117x_Ecode_t SI117XDRV_RegisterPreFifoFlushCallback (SI117XDRV_DeviceSelect_t device, SI117XDRV_Callback_t callback, void *user);
Si117x_Ecode_t SI117XDRV_RegisterPostFifoFlushCallback (SI117XDRV_DeviceSelect_t device, SI117XDRV_Callback_t callback, void *user);
Si117x_Ecode_t SI117XDRV_InitAPI (SI117XDRV_DeviceSelect_t device, HANDLE deviceHandle);


/***************************************************************************//**
 * Fifo/Interrupt Processing functions
 ******************************************************************************/
Si117x_Ecode_t SI117XDRV_ProcessLDInterrupt (SI117XDRV_DeviceSelect_t device);
Si117x_Ecode_t SI117XDRV_ProcessWDInterrupt (SI117XDRV_DeviceSelect_t device);
Si117x_Ecode_t SI117XDRV_ProcessFifoData(SI117XDRV_DeviceSelect_t device, uint8_t *fifoData, uint16_t fifo_length, uint16_t timestamp, uint16_t irqSequence, uint16_t *dlePacketBytes);
Si117x_Ecode_t SI117XDRV_InitializeSi117xFifoStateMachine(SI117XDRV_DeviceSelect_t device);
Si117x_Ecode_t SI117XDRV_ProcessPPGInterrupt (SI117XDRV_DeviceSelect_t device, uint8_t *fifoData, uint16_t timestamp, uint16_t irqSequence);

#ifdef __cplusplus
}
#endif

#endif   //SI117x_DRIVER_H
