#ifndef __DRIVER_QDEC_H__
#define __DRIVER_QDEC_H__

#include "driver_com.h"

//int qdec_init(void);

#define QDECX_DISABLE()                    (QDECXCON &= ~(0x1))
#define QDECY_DISABLE()                    (QDECYCON &= ~(0x1))
#define QDECZ_DISABLE()                    (QDECZCON &= ~(0x1))
#define QDECX_ENABLB()                     (QDECXCON |= 0x1)
#define QDECY_ENABLB()                     (QDECYCON |= 0x1)
#define QDECZ_ENABLB()                     (QDECZCON |= 0x1)

#define QDECX_INTERRUPT_REVERSE_ENABLE()   (QDECXCON |= 1 << 2)
#define QDECX_INTERRUPT_REVERSE_DISABLE()  (QDECXCON &= ~(1 << 2))
#define QDECY_INTERRUPT_REVERSE_ENABLE()   (QDECYCON |= 1 << 2)
#define QDECY_INTERRUPT_REVERSE_DISABLE()  (QDECYCON &= ~(1 << 2))
#define QDECZ_INTERRUPT_REVERSE_ENABLE()   (QDECZCON |= 1 << 2)
#define QDECZ_INTERRUPT_REVERSE_DISABLE()  (QDECZCON &= ~(1 << 2))

#define QDECX_INTERRUPT_FORWARD_ENABLE()   (QDECXCON |= 1 << 1)
#define QDECX_INTERRUPT_FORWARD_DISABLE()  (QDECXCON &= ~(1 << 1))
#define QDECY_INTERRUPT_FORWARD_ENABLE()   (QDECYCON |= 1 << 1)
#define QDECY_INTERRUPT_FORWARD_DISABLE()  (QDECYCON &= ~(1 << 1))
#define QDECZ_INTERRUPT_FORWARD_ENABLE()   (QDECZCON |= 1 << 1)
#define QDECZ_INTERRUPT_FORWARD_DISABLE()  (QDECZCON &= ~(1 << 1))

#define QDECX_INTERRUPT_SMPIE_ENABLE     (QDECXCON |= 1 << 3)
#define QDECX_INTERRUPT_SMPIE_DISABLE    (QDECXCON &= ~(1 << 3))
#define QDECY_INTERRUPT_SMPIE_ENABLE     (QDECYCON |= 1 << 3)
#define QDECY_INTERRUPT_SMPIE_DISABLE    (QDECYCON &= ~(1 << 3))
#define QDECZ_INTERRUPT_SMPIE_ENABLE     (QDECZCON |= 1 << 3)
#define QDECZ_INTERRUPT_SMPIE_DISABLE    (QDECZCON &= ~(1 << 3))

#define QDECX_WKUP_ENABLE()                (QDECXCON |= 1 << 4)
#define QDECX_WKUP_DISABLE()               (QDECXCON &= ~(1 << 4))
#define QDECY_WKUP_ENABLE()                (QDECYCON |= 1 << 4)
#define QDECY_WKUP_DISABLE()               (QDECYCON &= ~(1 << 4))
#define QDECZ_WKUP_ENABLE()                (QDECZCON |= 1 << 4)
#define QDECZ_WKUP_DISABLE()               (QDECZCON &= ~(1 << 4))

/*5~11BIT*/
#define QDECX_FILTER(x)                  (QDECXCON &= ~(0x7f << 5),QDECXCON |= ((x & 0x7f) << 5))
#define QDECY_FILTER(x)                  (QDECYCON &= ~(0x7f << 5),QDECYCON |= ((x & 0x7f) << 5))
#define QDECZ_FILTER(x)                  (QDECZCON &= ~(0x7f << 5),QDECZCON |= ((x & 0x7f) << 5))
#define QDECX_FILTER_CLEAR               (QDECXCON &= ~(0x7f << 5))
#define QDECY_FILTER_CLEAR               (QDECYCON &= ~(0x7f << 5))
#define QDECZ_FILTER_CLEAR               (QDECZCON &= ~(0x7f << 5))

/*bit 12~13
select mode cap1/2/4 edge*/
#define QDECX_MODE_CAP1()                  (QDECXCON &= ~(3 << 12))
#define QDECX_MODE_CAP2()                  (QDECXCON |= (2 << 12))
#define QDECX_MODE_CAP4()                  (QDECXCON |= (3 << 12))
#define QDECY_MODE_CAP1()                  (QDECYCON &= ~(3 << 12))
#define QDECY_MODE_CAP2()                  (QDECYCON |= (2 << 12))
#define QDECY_MODE_CAP4()                  (QDECYCON |= (3 << 12))
#define QDECZ_MODE_CAP1()                  (QDECZCON &= ~(3 << 12))
#define QDECZ_MODE_CAP2()                  (QDECZCON |= (2 << 12))
#define QDECZ_MODE_CAP4()                  (QDECZCON |= (3 << 12))

#define QDECX_ERROR_PENDING_GET          (QDECXCON & (1 << 14))
#define QDECY_ERROR_PENDING_GET          (QDECYCON & (1 << 14))
#define QDECZ_ERROR_PENDING_GET          (QDECZCON & (1 << 14))

//#define QDECX_MODE_WHEEL                 (QDECXCON |= 1 << 15)
//#define QDECX_MODE_NORMAL                (QDECXCON &= ~(1 << 15))
//#define QDECY_MODE_WHEEL                 (QDECYCON |= 1 << 15)
//#define QDECY_MODE_NORMAL                (QDECYCON &= ~(1 << 15))
//#define QDECZ_MODE_WHEEL                 (QDECZCON |= 1 << 15)
//#define QDECZ_MODE_NORMAL                (QDECZCON &= ~(1 << 15))

#define QDECX_TIME_MODE_ENABLE           (QDECXCON |= 1 << 15)
#define QDECX_TIME_MODE_DISABLE          (QDECXCON &= ~(1 << 15))
#define QDECY_TIME_MODE_ENABLE           (QDECYCON |= 1 << 15)
#define QDECY_TIME_MODE_DISABLE          (QDECYCON &= ~(1 << 15))
#define QDECZ_TIME_MODE_ENABLE           (QDECZCON |= 1 << 15)
#define QDECZ_TIME_MODE_DISABLE          (QDECZCON &= ~(1 << 15))
/*bit 16~19*/
#define QDECX_SMP(x)                     (QDECXCON |= (x & 0x0f) << 16)
#define QDECY_SMP(x)                     (QDECYCON |= (x & 0x0f) << 16)
#define QDECZ_SMP(x)                     (QDECZCON |= (x & 0x0f) << 16)

#define QDECX_SMP_PND                    (QDECXCON & (1 << 20))
#define QDECY_SMP_PND                    (QDECYCON & (1 << 20))
#define QDECZ_SMP_PND                    (QDECZCON & (1 << 20))

#define QDECX_OV_PNDING_GET              (QDECXCON & (1 << 21))
#define QDECY_OV_PNDING_GET              (QDECYCON & (1 << 21))
#define QDECZ_OV_PNDING_GET              (QDECZCON & (1 << 21))

#define QDECX_DAT_CLR                    (QDECXCON |= (1 << 22))
#define QDECY_DAT_CLR                    (QDECYCON |= (1 << 22))
#define QDECZ_DAT_CLR                    (QDECZCON |= (1 << 22))

#define QDECX_REVERSE_PENDING_GET        (QDECXCON & (1 << 31))
#define QDECX_FORWARD_PENDING_GET        (QDECXCON & (1 << 30))
#define QDECY_REVERSE_PENDING_GET        (QDECYCON & (1 << 31))
#define QDECY_FORWARD_PENDING_GET        (QDECYCON & (1 << 30))
#define QDECZ_REVERSE_PENDING_GET        (QDECZCON & (1 << 31))
#define QDECZ_FORWARD_PENDING_GET        (QDECZCON & (1 << 30))

#define QDECX_REVERSE_PENDING_CLEAR()      (QDECXCPND = 1 << 31)
#define QDECX_FORWARD_PENDING_CLEAR()      (QDECXCPND = 1 << 30)
//#define QDECX_REOV_PNDING_CLEAR          (QDECXCPND = 1 << 22)
#define QDECX_OV_PNDING_CLEAR()            (QDECXCPND = 1 << 21)
#define QDECX_SMP_PENDING_CLEAR()          (QDECXCPND = 1 << 20)
#define QDECX_ERROR_PENDING_CLEAR()        (QDECXCPND = 1 << 14)
#define QDECY_REVERSE_PENDING_CLEAR()      (QDECYCPND = 1 << 31)
#define QDECY_FORWARD_PENDING_CLEAR()      (QDECYCPND = 1 << 30)
//#define QDECY_REOV_PNDING_CLEAR          (QDECYCPND = 1 << 22)
#define QDECY_OV_PNDING_CLEAR()            (QDECYCPND = 1 << 21)
#define QDECY_SMP_PENDING_CLEAR            (QDECYCPND = 1 << 20)
#define QDECY_ERROR_PENDING_CLEAR()        (QDECYCPND = 1 << 14)
#define QDECZ_REVERSE_PENDING_CLEAR()      (QDECZCPND = 1 << 31)
#define QDECZ_FORWARD_PENDING_CLEAR()      (QDECZCPND = 1 << 30)
//#define QDECZ_REOV_PNDING_CLEAR          (QDECZCPND = 1 << 22)
#define QDECZ_OV_PNDING_CLEAR()            (QDECZCPND = 1 << 21)
#define QDECZ_SMP_PENDING_CLEAR()          (QDECZCPND = 1 << 20)
#define QDECZ_ERROR_PENDING_CLEAR()        (QDECZCPND = 1 << 14)

#define QDECXDATA_VALUE_GET(x)           (x = (QDECXDAT & 0X00000fff))
#define QDECXDATA_SYMBOL_GET(x)          (x = ((QDECXDAT & 0x00000800) >> 11))
#define QDECYDATA_VALUE_GET(x)           (x = (QDECYDAT & 0X00000fff))
#define QDECYDATA_SYMBOL_GET(x)          (x = ((QDECYDAT & 0x00000800) >> 11))
#define QDECZDATA_VALUE_GET(x)           (x = (QDECZDAT & 0X00000fff))
#define QDECZDATA_SYMBOL_GET(x)          (x = ((QDECZDAT & 0x00000800) >> 11))

#define QDECX_FROV_PNDING_CLEAR         (QDECXCPND = 1 << 21)
#define QDECX_FROV_PNDING_GET           (QDECXCON & (1 << 21))

//QDEC clk
#define XOSCCON_DI_EN_XOSC              10
#define XOSCCON_DI_EN_CKOUT3            26
#define XOSCCON_DI_EN_LDO               12

typedef enum{
    QDEC_X_AXIS,
    QDEC_Y_AXIS,
    QDEC_Z_AXIS,
}QDEC_AXIS_SEL;

typedef struct{
    QDEC_AXIS_SEL qdec_asis_sel;
    u8 number_samples_sel;
    u8 qdec_cm_sel;
}qdec_init_typedef;


enum{
    QDEC_SMP_NUM_SAMPLES_64        = 0x0,
    QDEC_SMP_NUM_SAMPLES_640       = 0x1,
    QDEC_SMP_NUM_SAMPLES_2560      = 0x2,
    QDEC_SMP_NUM_SAMPLES_5120      = 0x3,
    QDEC_SMP_NUM_SAMPLES_7680      = 0x4,
    QDEC_SMP_NUM_SAMPLES_10240     = 0x5,
    QDEC_SMP_NUM_SAMPLES_12800     = 0x6,
    QDEC_SMP_NUM_SAMPLES_16360     = 0x7,
    QDEC_SMP_NUM_SAMPLES_17920     = 0x8,
};

enum{
    QDEC_CM_1_MODE                 = 0x1,
    QDEC_CM_2_MODE                 = 0x2,
    QDEC_CM_4_MODE                 = 0x3
};

void qdec_init(qdec_init_typedef *qdec_cfg);

#endif // __DRIVER_QDEC_H__
