#ifndef PIBOT_BOARD_H_
#define PIBOT_BOARD_H_

//class Queue;
#include "queue.h"
enum USART_NUMBER
{
    USART_1 = 1,
    USART_2,
    USART_3,
    USART_4,
    USART_5,
    USART_6,
};

enum MOTOR_ID
{
    MOTOR_1 = 0,
    MOTOR_2,
    MOTOR_3,
    MOTOR_4
};

#define PIN_MODE_INPUT 0x0
#define PIN_MODE_OUTPUT 0x1
#define PIN_MODE_INPUT_PULLUP 0x2

//output
#define _RUN_LED          0
#define _JS_CMD          1
#define _JS_CS          2
#define _JS_CLK          3

//input
#define _JS_DAT       0

class Board
{
public:
    virtual void init()=0;
    virtual void enable_irq()=0;
    virtual void disable_irq()=0;
    virtual void usart_debug_init()=0;
    virtual void usart_init(unsigned char num, unsigned long buad)=0;
    virtual Queue* usart_getDataQueue(unsigned char num)=0;

    virtual void usart_write(unsigned char num, unsigned char ch)=0;
    virtual void usart_write(unsigned char num, unsigned char* data, unsigned char len)=0;

    virtual void set_config(unsigned char* data, unsigned short len)=0;
    virtual void get_config(unsigned char* data, unsigned short len)=0;

    virtual unsigned long get_tick_count()=0;

    virtual void setDOState(unsigned char led_id, unsigned char operation) = 0;
    virtual bool getDIState(unsigned char id) = 0;

    virtual void motor_init(unsigned char num, unsigned long period)=0;
    virtual void motor_pwm(unsigned char num, long pwm_value)=0;

    virtual void encoder_init(unsigned char motor_id) = 0;
    virtual long get_encoder_count(unsigned char motor_id) = 0;

    virtual void i2c_init() = 0;
    virtual unsigned char i2c_write_byte(unsigned char equipment_address, unsigned char reg_address , unsigned char pt_char)=0;
    virtual unsigned char i2c_write_buf(unsigned char equipment_address, unsigned char reg_address , unsigned char* pt_char , unsigned char size) = 0;
    virtual unsigned char i2c_read_byte(unsigned char equipment_address, unsigned char reg_address , unsigned char* pt_char) = 0;
    virtual unsigned char i2c_read_buf(unsigned char equipment_address, unsigned char reg_address , unsigned char* pt_char , unsigned char size) = 0;

    unsigned char i2c_write_bit(unsigned char equipment_address, unsigned char reg_address, unsigned char bitNum, unsigned char data){
        unsigned char b=0;
        i2c_read_byte(equipment_address, reg_address, &b);
        b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
        return i2c_write_byte(equipment_address, reg_address, b);
    }

    unsigned char i2c_write_bits(unsigned char devAddr, unsigned char regAddr, unsigned char bitStart, unsigned char length, unsigned char data) {
        unsigned char b;
        if (i2c_read_byte(devAddr, regAddr, &b) != 0) {
            unsigned char mask = ((1 << length) - 1) << (bitStart - length + 1);
            data <<= (bitStart - length + 1); // shift data into correct position
            data &= mask; // zero all non-important bits in data
            b &= ~(mask); // zero all important bits in existing byte
            b |= data; // combine data with existing byte
            return i2c_write_byte(devAddr, regAddr, b);
        } else {
            return 0;
        }
    }

    int i2c_read_bits(unsigned char devAddr, unsigned char regAddr, unsigned char bitStart, unsigned char length, unsigned char *data) {
        unsigned char count, b;
        if ((count = i2c_read_byte(devAddr, regAddr, &b)) != 0) {
            unsigned char mask = ((1 << length) - 1) << (bitStart - length + 1);
            b &= mask;
            b >>= (bitStart - length + 1);
            *data = b;
        }
        return count;
    }


    static Board* get();
};

#endif