/** 
 * @file    imu.h
 * @brief   LSM6DS3TR-C IMU module
 * @author  Kenny Tran
 * @date    Feb 28 2024
 * @version 0.0.1
 *
 * @section LICENSES
 * Copyright (C) Morgan Advanced Programmable Systems, Inc.
 */


#ifndef IMU_H_
#define IMU_H_


/*--------------------------------------------------------------------------------------------------
 * INCLUDE FILES
 *------------------------------------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

#include <zephyr/kernel.h>

#include "../bsp/imu_reg.h"

#include "../lib/errno.h"

/*--------------------------------------------------------------------------------------------------
 * MACROS & CONSTANTS
 *------------------------------------------------------------------------------------------------*/
#define IMU_TASK_PERIOD_MS                      (100)
#define IMU_TASK_STACK_SIZE                     (1024)
#define IMU_INTERRUPT_HANDLER_TASK_STACK_SIZE   (1024)
#define IMU_TASK_THREAD_PRIORITY                (9)
#define IMU_INTERRUPT_HANDLER_THREAD_PRIORITY   (3)

/*--------------------------------------------------------------------------------------------------
 * TYPE DEFINITIONS & ENUMERATIONS
 *------------------------------------------------------------------------------------------------*/
typedef enum IMU_int_source
{
    IMU_INT_SOURCE_NONE = 0,
    IMU_INT_SOURCE_WAKEUP,

    IMU_INT_SOURCE_COUNT
} IMU_int_source_e;

typedef enum IMU_sensor
{
    IMU_SENSOR_ACCEL = 0,
    IMU_SENSOR_GYRO,
    IMU_SENSOR_COUNT
} IMU_sensor_e;

typedef struct IMU_data
{
    float x;
    float y;
    float z;
} IMU_data_s;

typedef void (*IMU_cb_t) (void);

typedef enum IMU_int_mode_flags
{
    IMU_int_shot_capture_mode = 0, // bit 0, set when fifo threshold and single tap detection is rounted to INT1 pin
    IMU_int_wake_up_mode, // bit 1, set when wake up event is rounted to INT1 pin
} IMU_int_mode_flags_e;


/*--------------------------------------------------------------------------------------------------
 * GLOBAL VARIABLE
 *------------------------------------------------------------------------------------------------*/
extern struct k_sem shot_capture_sem;
extern volatile bool busy_wait_active;
extern volatile uint32_t imu_task_counter;
extern volatile uint32_t _interface_task_counter;
extern volatile uint32_t _interface_task_during_i2c_counter;


/*--------------------------------------------------------------------------------------------------
 * PUBLIC FUNCTION PROTOTYPES
 *------------------------------------------------------------------------------------------------*/
ERRNO_e IMU_init (void);
ERRNO_e IMU_int_cb_register (IMU_int_source_e src, IMU_cb_t cb);

/* Gyro Fields Accessors*/
ERRNO_e IMU_gyro_enable(bool en);
ERRNO_e IMU_is_gyro_enabled(bool *en);
ERRNO_e IMU_set_fs_g(LSM6DS3TR_C_FS_G_ABSTR_e value);
ERRNO_e IMU_get_fs_g(LSM6DS3TR_C_FS_G_ABSTR_e* value);
ERRNO_e IMU_set_odr_g(LSM6DS3TR_C_ODR_G_e value);
ERRNO_e IMU_get_odr_g(LSM6DS3TR_C_ODR_G_e *value);
ERRNO_e IMU_set_hp_en_g(LSM6DS3TR_C_HP_EN_G_e value);
ERRNO_e IMU_get_hp_en_g(LSM6DS3TR_C_HP_EN_G_e *value);
ERRNO_e IMU_set_hpm_g(LSM6DS3TR_C_HPM_G_e value);
ERRNO_e IMU_get_hpm_g(LSM6DS3TR_C_HPM_G_e *value);
ERRNO_e IMU_set_lpf1_sel_g(LSM6DS3TR_C_LPF1_SEL_G_e value);
ERRNO_e IMU_get_lpf1_sel_g(LSM6DS3TR_C_LPF1_SEL_G_e* value);
ERRNO_e IMU_set_ftype(LSM6DS3TR_C_FTYPE_e value);
ERRNO_e IMU_get_ftype(LSM6DS3TR_C_FTYPE_e *value);

/* Accelerometer Fields Accessors */
ERRNO_e IMU_xl_enable (bool en);
ERRNO_e IMU_is_xl_enabled (bool *en);
ERRNO_e IMU_set_fs_xl(LSM6DS3TR_C_FS_XL_e value);
ERRNO_e IMU_get_fs_xl(LSM6DS3TR_C_FS_XL_e *value);
ERRNO_e IMU_set_odr_xl(LSM6DS3TR_C_ODR_XL_e value);
ERRNO_e IMU_get_odr_xl(LSM6DS3TR_C_ODR_XL_e *value);
ERRNO_e IMU_set_lpf1_bw_sel(LSM6DS3TR_C_LPF1_BW_SEL_e value);
ERRNO_e IMU_get_lpf1_bw_sel(LSM6DS3TR_C_LPF1_BW_SEL_e *value);
ERRNO_e IMU_set_lpf2_xl_en(LSM6DS3TR_C_LPF2_XL_EN_e value);
ERRNO_e IMU_get_lpf2_xl_en(LSM6DS3TR_C_LPF2_XL_EN_e *value);
ERRNO_e IMU_set_hp_slope_xl_en(LSM6DS3TR_C_HP_SLOPE_XL_EN_e value);
ERRNO_e IMU_get_hp_slope_xl_en(LSM6DS3TR_C_HP_SLOPE_XL_EN_e *value);
ERRNO_e IMU_set_hpcf_xl(LSM6DS3TR_C_HPCF_XL_e value);
ERRNO_e IMU_get_hpcf_xl(LSM6DS3TR_C_HPCF_XL_e *value);
ERRNO_e IMU_set_input_composite(LSM6DS3TR_C_INPUT_COMPOSITE_e value);
ERRNO_e IMU_get_input_composite(LSM6DS3TR_C_INPUT_COMPOSITE_e *value);

/* FIFO Fields Accessors*/
ERRNO_e IMU_set_FTH(uint16_t value);
ERRNO_e IMU_get_FTH(uint16_t *value);
ERRNO_e IMU_set_dec_fifo_gyro(LSM6DS3TR_C_DEC_FIFO_GYRO_e value);
ERRNO_e IMU_get_dec_fifo_gyro(LSM6DS3TR_C_DEC_FIFO_GYRO_e *value);
ERRNO_e IMU_set_dec_fifo_xl(LSM6DS3TR_C_DEC_FIFO_XL_e value);
ERRNO_e IMU_get_dec_fifo_xl(LSM6DS3TR_C_DEC_FIFO_XL_e *value);
ERRNO_e IMU_set_odr_fifo(LSM6DS3TR_C_ODR_FIFO_e value);
ERRNO_e IMU_get_odr_fifo(LSM6DS3TR_C_ODR_FIFO_e *value);
ERRNO_e IMU_set_fifo_mode(LSM6DS3TR_C_FIFO_MODE_e value);
ERRNO_e IMU_get_fifo_mode(LSM6DS3TR_C_FIFO_MODE_e *value);

/* Other Fields Accessors */
ERRNO_e IMU_set_int1_fth(LSM6DS3TR_C_INT1_FTH_e value);
ERRNO_e IMU_get_int1_fth(LSM6DS3TR_C_INT1_FTH_e *value);
ERRNO_e IMU_set_bdu(LSM6DS3TR_C_BDU_e value);
ERRNO_e IMU_get_bdu(LSM6DS3TR_C_BDU_e *value);
ERRNO_e IMU_set_interrupts_enable(LSM6DS3TR_C_INTERRUPTS_ENABLE_e value);
ERRNO_e IMU_get_interrupts_enable(LSM6DS3TR_C_INTERRUPTS_ENABLE_e *value);
ERRNO_e IMU_set_tap_x_en(LSM6DS3TR_C_TAP_X_EN_e value);
ERRNO_e IMU_get_tap_x_en(LSM6DS3TR_C_TAP_X_EN_e *value);
ERRNO_e IMU_set_tap_y_en(LSM6DS3TR_C_TAP_Y_EN_e value);
ERRNO_e IMU_get_tap_y_en(LSM6DS3TR_C_TAP_Y_EN_e *value);
ERRNO_e IMU_set_tap_z_en(LSM6DS3TR_C_TAP_Z_EN_e value);
ERRNO_e IMU_get_tap_z_en(LSM6DS3TR_C_TAP_Z_EN_e *value);
ERRNO_e IMU_set_lir(LSM6DS3TR_C_LIR_e value);
ERRNO_e IMU_get_lir(LSM6DS3TR_C_LIR_e *value);
ERRNO_e IMU_set_tap_ths(uint8_t value);
ERRNO_e IMU_get_tap_ths(uint8_t *value);
ERRNO_e IMU_set_quiet(LSM6DS3TR_C_QUIET_e value);
ERRNO_e IMU_get_quiet(LSM6DS3TR_C_QUIET_e *value);
ERRNO_e IMU_set_shock(LSM6DS3TR_C_SHOCK_e value);
ERRNO_e IMU_get_shock(LSM6DS3TR_C_SHOCK_e *value);
ERRNO_e IMU_set_single_double_tap(LSM6DS3TR_C_SINGLE_DOUBLE_TAP_e value);
ERRNO_e IMU_get_single_double_tap(LSM6DS3TR_C_SINGLE_DOUBLE_TAP_e *value);
ERRNO_e IMU_set_wk_ths(uint8_t value);
ERRNO_e IMU_get_wk_ths(uint8_t *value);
ERRNO_e IMU_set_wake_dur(LSM6DS3TR_C_WAKE_DUR_e value);
ERRNO_e IMU_get_wake_dur(LSM6DS3TR_C_WAKE_DUR_e *value);
ERRNO_e IMU_set_int1_single_tap(LSM6DS3TR_C_INT1_SINGLE_TAP_e value);
ERRNO_e IMU_get_int1_single_tap(LSM6DS3TR_C_INT1_SINGLE_TAP_e *value);
ERRNO_e IMU_set_int1_double_tap(LSM6DS3TR_C_INT1_DOUBLE_TAP_e value);
ERRNO_e IMU_get_int1_double_tap(LSM6DS3TR_C_INT1_DOUBLE_TAP_e *value);

ERRNO_e IMU_temp_raw_read (int16_t *p_dest);
ERRNO_e IMU_temp_c_read (float *p_dest);
ERRNO_e IMU_temp_f_read (float *p_dest);
ERRNO_e IMU_reset (void);
ERRNO_e IMU_xl_raw_x_read (int16_t *p_dest);
ERRNO_e IMU_xl_raw_y_read (int16_t *p_dest);
ERRNO_e IMU_xl_raw_z_read (int16_t *p_dest);
ERRNO_e IMU_xl_x_read (float *p_dest);
ERRNO_e IMU_xl_y_read (float *p_dest);
ERRNO_e IMU_xl_z_read (float *p_dest);
ERRNO_e IMU_xl_read (IMU_data_s *p_dest);
ERRNO_e IMU_gyro_raw_x_read (int16_t *p_dest);
ERRNO_e IMU_gyro_raw_y_read (int16_t *p_dest);
ERRNO_e IMU_gyro_raw_z_read (int16_t *p_dest);
ERRNO_e IMU_gyro_x_read (float *p_dest);
ERRNO_e IMU_gyro_y_read (float *p_dest);
ERRNO_e IMU_gyro_z_read (float *p_dest);
ERRNO_e IMU_gyro_read (IMU_data_s *p_dest);


void IMU_set_shot_capture_mode(bool enable);
ERRNO_e IMU_fifo_status_1to2_read (uint16_t *unread_words, uint8_t *empty, uint8_t *full_smart, uint8_t *over_run, uint8_t *waterM);
ERRNO_e IMU_func_src1_read (uint8_t *sign_motion);
ERRNO_e IMU_fifo_th_set(uint16_t fifo_threshold);
bool IMU_is_fifo_set(void);

ERRNO_e IMU_motion_int_enable (bool en, uint8_t threshold, uint8_t duration);
ERRNO_e IMU_sleep (void);

void IMU_task_install(void);
void IMU_interrupt_handler_task_install(void);
void Dummy_task_install (void);

void IMU_cli_cmd (int32_t argc, char **argv);
ERRNO_e IMU_fifo_th_set(uint16_t fifo_threshold);

#endif /* IMU_H_ */