/* Рыба, основные процедуры, без SDK Telink */
#define MIN_TSPS_US 400 // 400 us
#define SMPS_BLK_CNT 116 // ((20+27*7-2)/2)&0xFFFE = 102 or ((20+27*8-2)/2)&0xFFFE = 116
#define DLE_DATA_SIZE (SMPS_BLK_CNT*2+2)
#define MTU_DATA_SIZE (DLE_DATA_SIZE+7) // -(3 байта заголовка ATT и 4 байта заголовка L2CAP)
typedef struct __attribute__((packed)) _reg_rd_t{
uint8_t dev_addr; // адрес на шине i2c
uint8_t reg_addr; // номер регистра чтения
} reg_rd_t;
typedef struct __attribute__((packed)) _reg_wr_t{
uint8_t dev_addr; // адрес на шине i2c
uint8_t reg_addr; // номер регистра чтения
uint16_t data; // значение для записи в регистр
} reg_wr_t;
#define MAX_INIT_REGS 4
#define MAX_READ_REGS 4
// Структура конфигурации опроса и инициализации устройства
// Выходной пакет непрерывного опроса формируется по данному описанию
typedef struct __attribute__((packed)) _dev_cfg_t {
uint8_t rd_count; // кол-во регистров для разового чтения
uint8_t init_count; // кол-во регистров для инициализации
uint8_t multiplier; // множитель периода опроса, time << multiplier
uint8_t pktcnt; // кол-во передаваемых значений из регистров в одном пакете передачи
uint16_t time; // период опроса регистров чтения в us
uint16_t clk_khz; // частота i2c шины в kHz
reg_wr_t init[MAX_INIT_REGS];
reg_rd_t rd[MAX_READ_REGS];
} dev_cfg_t; // 8 + 4*4 + 2*4
// DEV_I2C cmd:
#define CMD_DI2C_VER 0x00 // Get Ver
#define CMD_DI2C_CFG 0x01 // Get/Set CFG/ini & Start measure
#define CMD_DI2C_SCF 0x02 // Store CFG/ini in Flash
#define CMD_DI2C_STA 0x03 // Status
#define CMD_DI2C_CPU 0x04 // Connect parameters Update (BLE)
#define CMD_DI2C_BLK 0x07 // blk out regs data
#define CMD_DI2C_ERR 0x0f // Runtime Error
#define CMD_DI2C_GRG 0x10 // Get reg
#define CMD_DI2C_SRG 0x11 // Set reg
//
#define CMD_ERR_FLG 0x80 // send error cmd mask
//
typedef struct __attribute__((packed)) {
uint8_t size; // размер пакета
uint8_t cmd; // номер команды / тип пакета
} blk_head_t;
typedef struct __attribute__((packed)) _blk_tx_pkt_t{
blk_head_t head;
union __attribute__((packed)) {
uint8_t uc[MTU_DATA_SIZE-sizeof(blk_head_t)];
int8_t sc[MTU_DATA_SIZE-sizeof(blk_head_t)];
uint16_t ui[(MTU_DATA_SIZE-sizeof(blk_head_t))/sizeof(uint16_t)];
int16_t si[(MTU_DATA_SIZE-sizeof(blk_head_t))/sizeof(int16_t)];
uint32_t ud[(MTU_DATA_SIZE-sizeof(blk_head_t))/sizeof(uint32_t)];
int32_t sd[(MTU_DATA_SIZE-sizeof(blk_head_t))/sizeof(uint32_t)];
reg_wr_t reg;
} data;
} blk_tx_pkt_t;
#define MTU_RX_DATA_SIZE (sizeof(blk_head_t) + sizeof(dev_cfg_t))
typedef struct __attribute__((packed)) _blk_rx_pkt_t{
blk_head_t head;
union __attribute__((packed)) {
uint8_t uc[MTU_RX_DATA_SIZE-sizeof(blk_head_t)];
int8_t sc[MTU_RX_DATA_SIZE-sizeof(blk_head_t)];
uint16_t ui[(MTU_RX_DATA_SIZE-sizeof(blk_head_t))/sizeof(uint16_t)];
int16_t si[(MTU_RX_DATA_SIZE-sizeof(blk_head_t))/sizeof(int16_t)];
uint32_t ud[(MTU_RX_DATA_SIZE-sizeof(blk_head_t))/sizeof(uint32_t)];
int32_t sd[(MTU_RX_DATA_SIZE-sizeof(blk_head_t))/sizeof(uint32_t)];
dev_cfg_t cfg;
reg_wr_t reg;
} data;
} blk_rx_pkt_t;
extern blk_rx_pkt_t read_pkt;
extern blk_tx_pkt_t send_pkt;
u32 tick_wakeup;
u8 ui_ota_is_working = 0;
u8 device_in_connection_state = 0;
u8 ui_mtu_size_exchange_req = 0;
u8 wrk_enable = 0;
u8 wrk_tick = 0;
u8 rx_len = 0;
u8 tx_len = 0;
blk_rx_pkt_t read_pkt;
blk_tx_pkt_t send_pkt;
volatile uint8_t timer_flg = 0;
u32 all_rd_count = 0;
u32 not_send_count = 0;
u16 buf[256];
u32 buf_wr = 0;
u32 buf_rd = 0;
u8 rd_next_cnt;
// I2C device GetNewRegData
// Called from Irq (!) Timer
_attribute_ram_code_ void GetNewRegData(void) {
if (rd_next_cnt >= cfg_ini.rd_count) rd_next_cnt = 0;
reg_rd_t * raddr = &cfg_ini.rd[rd_next_cnt++];
I2CBusReadWord(raddr->dev_addr, raddr->reg_addr, &buf[buf_wr]);
all_rd_count++;
buf_wr++;
buf_wr &= 255;
}
// Define USB rx/tx buffer
#define RX_BUF_LEN USB_CDC_MAX_RX_BLK_SIZE // in bytes
#define TX_BUF_LEN MTU_DATA_SIZE // in bytes (MTU BLE)
#define RX_BUF_NUM 2
static unsigned char rx_buf[RX_BUF_NUM][RX_BUF_LEN];
static unsigned char tx_buf[TX_BUF_LEN];
static unsigned char rx_ptr = 0;
volatile u8 usb_actived;
void Timer_Stop(void) {
timer_flg = 0;
reg_tmr1_tick = 0;
reg_tmr_sta = FLD_TMR_STA_TMR1;
reg_irq_mask1 &= ~FLD_IRQ_TMR1_EN;
reg_tmr_ctrl8 &= ~FLD_TMR1_EN;
}
void Timer_Init(uint32_t period_us) {
reg_tmr1_tick = 0;
reg_tmr1_capt = period_us * CLOCK_SYS_CLOCK_1US;
reg_tmr_ctrl8 |= FLD_TMR1_EN; // FLD_TMR1_MODE = 0
reg_irq_mask1 |= FLD_IRQ_TMR1_EN;
reg_tmr_sta = FLD_TMR_STA_TMR1; // clear irq status
}
int InitExtI2CDevice(void) {
u32 i;
timer_flg = 0;
pkt_smp_max = 2;
if(cfg_ini.clk_khz < 100 || cfg_ini.clk_khz > 2500)
cfg_ini.clk_khz = 1000;
I2CBusInit(cfg_ini.clk_khz * 1000);
if(cfg_ini.rd_count > MAX_READ_REGS) cfg_ini.rd_count = 0;
u32 t_us = cfg_ini.time << cfg_ini.multiplier;
// ~ 30 us on 1 MHz I2C CLK (5 us + 25 us)
if(usb_actived) i = 30;
else i = MIN_TSPS_US;
if(i < t_us && t_us > 0xffffffff/CLOCK_SYS_CLOCK_1US) {
cfg_ini.rd_count = 0;
Timer_Stop();
return 0;
}
if (cfg_ini.rd_count) {
Timer_Init(t_us);
if(cfg_ini.pktcnt != 0 && cfg_ini.pktcnt <= SMPS_BLK_CNT)
pkt_smp_max = cfg_ini.pktcnt;
} else {
Timer_Stop();
}
all_rd_count = 0;
not_send_count = 0;
if (cfg_ini.init_count > MAX_INIT_REGS) cfg_ini.init_count = 0;
else for(i = 0; i < cfg_ini.init_count ; i++) {
if (!I2CBusWriteWord(cfg_ini.init[i].dev_addr, cfg_ini.init[i].reg_addr, cfg_ini.init[i].data)) {
Timer_Stop();
return 0;
}
}
rd_next_cnt = 0;
buf_wr = 0;
buf_rd = 0;
return 1;
}
/*******************************************************************************
* Function Name : usb_ble_cmd_loop.
* Description : Main loop routine.
* Input : blk_tx_pkt_t * pbufo, blk_tx_pkt_t * pbufi, int rxlen
* Return : txlen.
*******************************************************************************/
unsigned int cmd_loop(blk_tx_pkt_t * pbufo, blk_rx_pkt_t * pbufi, unsigned int rxlen) {
unsigned int txlen = 0;
pbufo->head.cmd = pbufi->head.cmd;
switch (pbufi->head.cmd) {
case CMD_DI2C_VER: // Get Ver
pbufo->data.ui[0] = 0x1016; // DevID = 0x1016
pbufo->data.ui[1] = 0x0007; // Ver 0.0.0.7 = 0x0007
txlen = sizeof(u16) + sizeof(u16) + sizeof(blk_head_t);
break;
case CMD_DI2C_CFG: // Get/Set CFG/ini & Start measure
if (pbufi->head.size) {
timer_flg = 0;
memcpy(&cfg_ini, &pbufi->data,
(pbufi->head.size > sizeof(cfg_ini))? sizeof(cfg_ini) : pbufi->head.size);
if (!InitExtI2CDevice()) {
pbufo->head.cmd |= CMD_ERR_FLG; // Error cmd
txlen = 0 + sizeof(blk_head_t);
break;
}
timer_flg = 1;
}
memcpy(&pbufo->data, &cfg_ini, sizeof(cfg_ini));
txlen = sizeof(cfg_ini) + sizeof(blk_head_t);
break;
case CMD_DI2C_SCF: // Store CFG/ini in Flash
flash_write_cfg(&cfg_ini, EEP_I2C_CFG_ID, sizeof(cfg_ini));
txlen = sizeof(blk_head_t);
break;
case CMD_DI2C_STA: // Status
pbufo->data.ud[0] = all_rd_count;
pbufo->data.ud[1] = not_send_count;
txlen = 8 + sizeof(blk_head_t);
break;
//-------
case CMD_DI2C_CPU: // Connect parameters Update
if(!usb_actived) {
if (pbufi->head.size)
bls_l2cap_requestConnParamUpdate(pbufi->data.ui[0],pbufi->data.ui[1],pbufi->data.ui[2],pbufi->data.ui[3]);
extern void blt_get_conn_para(u8 * x);
blt_get_conn_para((u8 *)&pbufi->data);
txlen = 8 + sizeof(blk_head_t);
} else {
pbufo->head.cmd |= CMD_ERR_FLG; // Error cmd
txlen = 0 + sizeof(blk_head_t);
}
break;
//-------
case CMD_DI2C_GRG: // Get reg
timer_flg = 0;
if (I2CBusReadWord(pbufi->data.reg.dev_addr, pbufi->data.reg.reg_addr,
(uint16_t *)&pbufo->data.reg.data)) {
pbufo->data.ui[0] = pbufi->data.ui[0];
timer_flg = 1;
txlen = sizeof(reg_wr_t) + sizeof(blk_head_t);
} else {
timer_flg = 1;
pbufo->head.cmd |= CMD_ERR_FLG; // Error cmd
txlen = 0 + sizeof(blk_head_t);
};
break;
case CMD_DI2C_SRG: // Set reg
timer_flg = 0;
if (I2CBusWriteWord(pbufi->data.reg.dev_addr, pbufi->data.reg.reg_addr,
pbufi->data.reg.data)) {
pbufo->data.reg = pbufi->data.reg;
timer_flg = 1;
txlen = sizeof(reg_wr_t) + sizeof(blk_head_t);
} else {
timer_flg = 1;
pbufo->head.cmd |= CMD_ERR_FLG; // Error cmd
txlen = 0 + sizeof(blk_head_t);
};
break;
default:
pbufo->head.cmd |= CMD_ERR_FLG; // Error cmd
txlen = 0 + sizeof(blk_head_t);
break;
};
pbufo->head.size = txlen - sizeof(blk_head_t);
return txlen;
}