/*
 * lis2dw.h
 *
 *  Created on: Jul 28, 2024
 *      Author: true
 */

#ifndef USER_HW_LIS2DW_H_
#define USER_HW_LIS2DW_H_


#include "comm/i2c.h"


#define LIS2DW_I2C_ADDR             0x30
#define LIS2DW_I2C_ADDR_SDO_LOW     0x32

#define lis2dw_i2c_read(a, d, s)    i2c_read(a, d, s);
#define lis2dw_i2c_write(a, d, s)   i2c_write(a, d, s);


// driver constants


// registers
#define LIS2DW_REG_OUT_T_L          0x0d
#define LIS2DW_REG_OUT_T_H          0x0e
#define LIS2DW_REG_WHO_AM_I         0x0f
#define LIS2DW_REG_CTRL1            0x20
#define LIS2DW_REG_CTRL2            0x21
#define LIS2DW_REG_CTRL3            0x22
#define LIS2DW_REG_CTRL4            0x23
#define LIS2DW_REG_INT1_PAD         0x23    // default: 0x00
#define LIS2DW_REG_CTRL5            0x24
#define LIS2DW_REG_INT2_PAD         0x24    // default: 0x00
#define LIS2DW_REG_CTRL6            0x25
#define LIS2DW_REG_OUT_T            0x26
#define LIS2DW_REG_STATUS           0x27
#define LIS2DW_REG_OUT_X_L          0x28
#define LIS2DW_REG_OUT_X_H          0x29
#define LIS2DW_REG_OUT_Y_L          0x2a
#define LIS2DW_REG_OUT_Y_H          0x2b
#define LIS2DW_REG_OUT_Z_L          0x2c
#define LIS2DW_REG_OUT_Z_H          0x2d
#define LIS2DW_REG_FIFO_CTRL        0x2e
#define LIS2DW_REG_FIFO_SAMPLES     0x2f
#define LIS2DW_REG_TAP_THS_X        0x30
#define LIS2DW_REG_TAP_THS_Y        0x31
#define LIS2DW_REG_TAP_THS_Z        0x32
#define LIS2DW_REG_INT_DUR          0x33
#define LIS2DW_REG_WAKE_UP_THS      0x34
#define LIS2DW_REG_WAKE_UP_DUR      0x35
#define LIS2DW_REG_FREE_FALL        0x36
#define LIS2DW_REG_STATUS_DUP       0x37
#define LIS2DW_REG_WAKE_UP_SRC      0x38
#define LIS2DW_REG_TAP_SRC          0x39
#define LIS2DW_REG_SIXD_SRC         0x3a
#define LIS2DW_REG_ALL_INT_SRC      0x3b    // read this register to clear all INT pins
#define LIS2DW_REG_X_OFS_USR        0x3c
#define LIS2DW_REG_Y_OFS_USR        0x3d
#define LIS2DW_REG_Z_OFS_USR        0x3e
#define LIS2DW_REG_CTRL_REG7        0x3f
#define LIS2DW_REG_CTRL7            0x3f

// register properties
#define LIS2DW_WHO_AM_I                 0x44

#define LIS2DW_CTRL1_LP_MODE_SHIFT      0
enum LIS2DW_CTRL1_LP_Mode {
    LIS2DW_CTRL1_LP_MODE1 = 0,
    LIS2DW_CTRL1_LP_MODE2,
    LIS2DW_CTRL1_LP_MODE3,
    LIS2DW_CTRL1_LP_MODE4
};

#define LIS2DW_CTRL1_MODE_LO_POWR       (0 << 2)
#define LIS2DW_CTRL1_MODE_HI_PERF       (1 << 2)
#define LIS2DW_CTRL1_MODE_SNGL_DATA     (2 << 2)

#define LI22DW_CTRL1_DATA_RATE_SHIFT    4
enum LIS2DW_CTRL1_Data_Rate {
    LIS2DW_CTRL1_DATA_RATE_PWR_DOWN = 0,
    LIS2DW_CTRL1_DATA_RATE_1_6,                     // 12.5 in high power mode
    LIS2DW_CTRL1_DATA_RATE_12_5,
    LIS2DW_CTRL1_DATA_RATE_25,
    LIS2DW_CTRL1_DATA_RATE_50,
    LIS2DW_CTRL1_DATA_RATE_100,
    LIS2DW_CTRL1_DATA_RATE_200,
    LIS2DW_CTRL1_DATA_RATE_400,                     // 200 in low power mode
    LIS2DW_CTRL1_DATA_RATE_800,                     // 200 in low power mode
    LIS2DW_CTRL1_DATA_RATE_1600                     // 200 in low power mode
};

#define LIS2DW_CTRL2_SPI_4_WIRE         (0 << 0)
#define LIS2DW_CTRL2_SPI_3_WIRE         (1 << 0)
#define LIS2DW_CTRL2_I2C_ENABLE         (0 << 1)
#define LIS2DW_CTRL2_I2C_DISABLE        (1 << 1)
#define LIS2DW_CTRL2_IF_ADDR_INC        (1 << 2)    // automatically increment register; roll back from 0x2d->0x28
#define LIS2DW_CTRL2_BLOCK_DATA_UPDATE  (1 << 3)    // only update data after both MSB+LSB read
#define LIS2DW_CTRL2_CS_PU_DISC         (1 << 4)
#define LIS2DW_CTRL2_SOFT_RESET         (1 << 6)    // resets all registers
#define LIS2DW_CTRL2_BOOT               (1 << 7)    // re-loads calibration constants

#define LIS2DW_CTRL3_SLP_MODE_1         (1 << 0)    // single data conversion on demand trigger
#define LIS2DW_CTRL3_SLP_MODE_SEL       (1 << 1)    // single data conversion on demand (0=INT2, 1=SLP_MODE_1)
#define LIS2DW_CTRL3_H_L_ACTIVE         (1 << 3)    // interrupt level. 0=active high, 1=active low
#define LIS2DW_CTRL3_LATCHED_IR         (1 << 4)    // signals latched. 0=not latched (pulse), 1=latched
#define LIS2DW_CTRL3_PP_OD              (1 << 5)    // push pull or open drain on interrupts. 0=pushpull, 1=opendrain
#define LIS2DW_CTRL3_SELFTEST_NONE      (0 << 6)
#define LIS2DW_CTRL3_SELFTEST_POS       (1 << 6)
#define LIS2DW_CTRL3_SELFTEST_NEG       (2 << 6)

#define LIS2DW_INT1_DRDY                (1 << 0)    // data ready
#define LIS2DW_INT1_FTH                 (1 << 1)    // fifo threshold
#define LIS2DW_INT1_DIFF5               (1 << 2)    // fifo full
#define LIS2DW_INT1_TAP                 (1 << 3)    // double tap
#define LIS2DW_INT1_FF                  (1 << 4)    // free fall
#define LIS2DW_INT1_WU                  (1 << 5)    // wakeup
#define LIS2DW_INT1_SINGLE_TAP          (1 << 6)    // single tap
#define LIS2DW_INT1_6D                  (1 << 7)    // 6D

#define LIS2DW_INT2_DRDY                (1 << 0)    // data ready
#define LIS2DW_INT2_FTH                 (1 << 1)    // fifo threshold
#define LIS2DW_INT2_DIFF5               (1 << 2)    // fifo full
#define LIS2DW_INT1_OVR                 (1 << 3)    // fifo overrun
#define LIS2DW_INT1_DRDY_TEMP           (1 << 4)    // temperature data ready
#define LIS2DW_INT1_BOOT                (1 << 5)    // boot
#define LIS2DW_INT1_SLEEP_CHG           (1 << 6)    // sleep change status
#define LIS2DW_INT1_SLEEP_STATE         (1 << 7)    // sleep state

#define LIS2DW_CTRL6_LOW_NOISE          (1 << 2)
#define LIS2DW_CTRL6_FILTER_DATA_SELECT (1 << 3)    // 0=low pass, 1=high pass
#define LIS2DW_CTRL6_FULLSCALE_2G       (0 << 4)
#define LIS2DW_CTRL6_FULLSCALE_4G       (1 << 4)
#define LIS2DW_CTRL6_FULLSCALE_8G       (2 << 4)
#define LIS2DW_CTRL6_FULLSCALE_16G      (3 << 4)
#define LIS2DW_CTRL6_BW_FILT_ODR_2      (0 << 6)
#define LIS2DW_CTRL6_BW_FILT_ODR_4      (1 << 6)
#define LIS2DW_CTRL6_BW_FILT_ODR_10     (2 << 6)
#define LIS2DW_CTRL6_BW_FILT_ODR_20     (3 << 6)

#define LIS2DW_STATUS_DRDY              (1 << 0)    // 0=nrdy, 1=x/y/z new data
#define LIS2DW_STATUS_FF_IA             (1 << 1)    // free fall event
#define LIS2DW_STATUS_6D_IA             (1 << 2)    // 6D change in pos detected
#define LIS2DW_STATUS_SINGLE_TAP        (1 << 3)
#define LIS2DW_STATUS_DOUBLE_TAP        (1 << 4)
#define LIS2DW_STATUS_SLEEP_STATE       (1 << 5)    // sleep event detected
#define LIS2DW_STATUS_WU_IA             (1 << 6)    // wakeup event detected
#define LIS2DW_STATUS_FIFO_THS          (1 << 7)    // fifo thresh; 1=equal or higher than threshold

#define LIS2DW_FIFO_THRESHOLD_MASK      0x1f
#define LIS2DW_FIFO_MODE_BYPASS         (0 << 4)
#define LIS2DW_FIFO_MODE_FIFO           (1 << 4)
#define LIS2DW_FIFO_MODE_CONT_TO_FIFO   (3 << 4)
#define LIS2DW_FIFO_MODE_BYPASS_TO_CONT (4 << 4)
#define LIS2DW_FIFO_MODE_CONT           (6 << 4)

#define LIS2DW_FIFO_SAMPLES_COUNT_MASK  0x3f
#define LIS2DW_FIFO_SAMPLES_OVERRUN     (1 << 6)    // 0=not filled, 1=filled and sample overwritten
#define LIS2DW_FIFO_SAMPLES_THRESHOLD   (1 << 7)    // 0=lower, 1=equal or higher

#define LIS2DW_TAP_THSX_THRESHOLD_MASK  0x1f
#define LIS2DW_TAP_6D_THRESHOLD_80DEG   (0 << 5)
#define LIS2DW_TAP_6D_THRESHOLD_70DEG   (1 << 5)
#define LIS2DW_TAP_6D_THRESHOLD_60DEG   (2 << 5)
#define LIS2DW_TAP_6D_THRESHOLD_50DEG   (3 << 5)
#define LIS2DW_TAP_4D_EN                (1 << 7)

#define LIS2DW_TAP_THSY_THRESHOLD_MASK  0x1f
#define LIS2DW_TAP_PRIO_XYZ             (0 << 5)
#define LIS2DW_TAP_PRIO_YXZ             (1 << 5)
#define LIS2DW_TAP_PRIO_XZY             (2 << 5)
#define LIS2DW_TAP_PRIO_ZYX             (3 << 5)
#define LIS2DW_TAP_PRIO_YZX             (5 << 5)
#define LIS2DW_TAP_PRIO_ZXY             (6 << 5)

#define LIS2DW_TAP_THSZ_THRESHOLD_MASK  0x1f
#define LIS2DW_TAP_Z_EN                 (1 << 5)
#define LIS2DW_TAP_Y_EN                 (1 << 6)
#define LIS2DW_TAP_X_EN                 (1 << 7)

#define LIS2DW_INT_DUR_SHOCK_4xODR      (0 << 0)    // tap event min signal threshold
#define LIS2DW_INT_DUR_SHOCK_8xODR      (1 << 0)    // data sheet isn't clear on durations
#define LIS2DW_INT_DUR_SHOCK_12xODR     (2 << 0)
#define LIS2DW_INT_DUR_SHOCK_16xODR     (3 << 0)
#define LIS2DW_INT_DUR_QUIET_4xODR      (0 << 2)    // post tap event quiet time threshold
#define LIS2DW_INT_DUR_QUIET_8xODR      (1 << 2)
#define LIS2DW_INT_DUR_QUIET_12xODR     (2 << 2)
#define LIS2DW_INT_DUR_QUIET_16xODR     (3 << 2)
#define LIS2DW_INT_DUR_LATENCY_16xODR   (0 << 4)    // double tap gap maximum time between events
#define LIS2DW_INT_DUR_LATENCY_32xODR   (1 << 4)
#define LIS2DW_INT_DUR_LATENCY_48xODR   (2 << 4)
#define LIS2DW_INT_DUR_LATENCY_64xODR   (3 << 4)
#define LIS2DW_INT_DUR_LATENCY_80xODR   (4 << 4)
#define LIS2DW_INT_DUR_LATENCY_96xODR   (5 << 4)
#define LIS2DW_INT_DUR_LATENCY_112xODR  (6 << 4)
#define LIS2DW_INT_DUR_LATENCY_128xODR  (7 << 4)

#define LIS2DW_WAKE_UP_THRESHOLD_MASK   0x3f        // 1 LSB = 1/64 of FS
#define LIS2DW_WAKE_UP_SLEEP_ON         (1 << 6)    // sleep enable / disable
#define LIS2DW_WAKE_UP_SNGL_DUBL_TAP    (1 << 7)    // enable single/double tap event, 0=single only, 1=both

#define LIS2DW_WAKE_UP_SLEEP_DUR_MASK   0x0f        // duration in sleep. 0=16*1/ODR, LSB=512*1/ODR
#define LIS2DW_WAKE_UP_DUR_STATIONARY   (1 << 4)    // stationary detection ena/dis
#define LIS2DW_WAKE_UP_DURATION_0       (0 << 5)
#define LIS2DW_WAKE_UP_DURATION_1       (1 << 5)
#define LIS2DW_WAKE_UP_DURATION_2       (2 << 5)
#define LIS2DW_WAKE_UP_DURATION_3       (3 << 5)
#define LIS2DW_WAKE_UP_FF_DUR5          (1 << 7)    // free fall duration, highest bit. see below.

#define LIS2DW_FREE_FALL_THRESHOLD_5    (0 << 0)    // freefall threshold @ +-2G FS in LSB counts
#define LIS2DW_FREE_FALL_THRESHOLD_7    (1 << 0)
#define LIS2DW_FREE_FALL_THRESHOLD_8    (2 << 0)
#define LIS2DW_FREE_FALL_THRESHOLD_10   (3 << 0)
#define LIS2DW_FREE_FALL_THRESHOLD_11   (4 << 0)
#define LIS2DW_FREE_FALL_THRESHOLD_13   (5 << 0)
#define LIS2DW_FREE_FALL_THRESHOLD_15   (6 << 0)
#define LIS2DW_FREE_FALL_THRESHOLD_16   (7 << 0)
#define LIS2DW_FREE_FALL_DUR14_MASK     0xf8        // free fall duration, lowest bits.  1 LSB = 1 * 1/ODR

#define LIS2DW_STATUS_DUP_DRDY          (1 << 0)    // 0=nrdy, 1=x/y/z new data
#define LIS2DW_STATUS_DUP_FF_IA         (1 << 1)    // free fall event
#define LIS2DW_STATUS_DUP_6D_IA         (1 << 2)    // 6D change in pos detected
#define LIS2DW_STATUS_DUP_SINGLE_TAP    (1 << 3)
#define LIS2DW_STATUS_DUP_DOUBLE_TAP    (1 << 4)
#define LIS2DW_STATUS_DUP_SLEEP_STATE   (1 << 5)    // sleep event detected
#define LIS2DW_STATUS_DUP_DRDY_TEMP     (1 << 6)    // new temperature data available
#define LIS2DW_STATUS_FIFO_OVERRUN      (1 << 7)    // fifo overrun. 1=filled completely and data overwritten

#define LIS2DW_WAKE_UP_SRC_Z            (1 << 0)
#define LIS2DW_WAKE_UP_SRC_Y            (1 << 1)
#define LIS2DW_WAKE_UP_SRC_X            (1 << 2)
#define LIS2DW_WAKE_UP_SRC_WU           (1 << 3)
#define LIS2DW_WAKE_UP_SRC_SLEEP_STATE  (1 << 4)
#define LIS2DW_WAKE_UP_SRC_FF           (1 << 5)

#define LIS2DW_TAP_SRC_Z_TAP            (1 << 0)
#define LIS2DW_TAP_SRC_Y_TAP            (1 << 1)
#define LIS2DW_TAP_SRC_X_TAP            (1 << 2)
#define LIS2DW_TAP_SRC_TAP_SIGN         (1 << 3)    // sign of detected tap acceleration
#define LIS2DW_TAP_SRC_DOUBLE_TAP       (1 << 4)    // double tap detected
#define LIS2DW_TAP_SRC_SINGLE_TAP       (1 << 5)    // single tap detected
#define LIS2DW_TAP_SRC_TAP_ANY          (1 << 6)    // tap of any kind detected

#define LIS2DW_6D_SRC_XL                (1 << 0)    // XL over threshold
#define LIS2DW_6D_SRC_XH                (1 << 1)    // XH over threshold
#define LIS2DW_6D_SRC_YL                (1 << 2)    // YL over threshold
#define LIS2DW_6D_SRC_YH                (1 << 3)    // YH over threshold
#define LIS2DW_6D_SRC_ZL                (1 << 4)    // ZL over threshold
#define LIS2DW_6D_SRC_ZH                (1 << 5)    // ZH over threshold
#define LIS2DW_6D_6D_POS_CHANGED        (1 << 6)    // position changed (portrait/landscape/faceup/facedown)

#define LIS2DW_ALL_INT_SRC_FF           (1 << 0)    // free fall event detected
#define LIS2DW_ALL_INT_SRC_WU           (1 << 0)    // wakeup event detected
#define LIS2DW_ALL_INT_SRC_SINGLE_TAP   (1 << 0)    // single tap status
#define LIS2DW_ALL_INT_SRC_DOUBLE_TAP   (1 << 0)    // double tap status
#define LIS2DW_ALL_INT_SRC_6D           (1 << 0)    // change in position
#define LIS2DW_ALL_INT_SRC_SLEEP_CHANGE (1 << 0)    // sleep change detected

#define LIS2DW_CTRL7_LPASS_ON6D         (1 << 0)    // 0=ODR/2 low pass data sent to 6D interrupt, 1=LPF2 sent to 6D interrupt
#define LIS2DW_CTRL7_HP_REF_MODE        (1 << 1)    // 1=high pass filter reference mode eanbled
#define LIS2DW_CTRL7_USR_OFF_W          (1 << 2)    // 0=977ug/LSB, 1=15.6mg/LSB. weight of user offset words
#define LIS2DW_CTRL7_USR_OFF_ON_WU      (1 << 3)    // user offset value on XL data for wakeup only
#define LIS2DW_CTRL7_USR_OFF_ON_OUT     (1 << 4)    // user offset value on XL output data registers (CTRL6_FDS must be set to 0)
#define LIS2DW_CTRL7_INTERRUPTS_ENABLE  (1 << 5)
#define LIS2DW_CTRL7_INT2_ON_INT1       (1 << 6)    // 1=INT2 signals are routed to INT1
#define LIS2DW_CTRL7_DRDY_PUSLED        (1 << 7)    // 0=latched mode, 1=pulsed mode for DRDY


// API
enum {
    LIS2DW_OP_MODE_HI_PERF     = 0x00,      // 14-bit, 90¦ÌA@200Hz, 12.5-1600Hz, 110¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_4    = 0x01,      // 14-bit, 63¦ÌA@200Hz, 1.6 - 200Hz, 160¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_3    = 0x02,      // 14-bit, 34¦ÌA@200Hz, 1.6 - 200Hz, 210¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_2    = 0x03,      // 14-bit, 20¦ÌA@200Hz, 1.6 - 200Hz, 300¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_1    = 0x04,      // 12-bit, 10¦ÌA@200Hz, 1.6 - 200Hz, 550¦Ìg/¡ÌHz

    LIS2DW_OP_MODE_HI_PERF_LN  = 0x10,      // 14-bit, 120¦ÌA@200,  12.5-1600Hz, 110¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_4_LN = 0x11,      // 14-bit, 77¦ÌA@200Hz, 1.6 - 200Hz, 160¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_3_LN = 0x12,      // 14-bit, 42¦ÌA@200Hz, 1.6 - 200Hz, 210¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_2_LN = 0x13,      // 14-bit, 25¦ÌA@200Hz, 1.6 - 200Hz, 300¦Ìg/¡ÌHz
    LIS2DW_OP_MODE_LO_PWR_1_LN = 0x14,      // 12-bit, 12¦ÌA@200Hz, 1.6 - 200Hz, 550¦Ìg/¡ÌHz
};



void lis2dw_init();



#endif /* USER_HW_LIS2DW_H_ */
