#include "app_config.h" #include "system/includes.h" #include "online_db_deal.h" #include "generic/circular_buf.h" #if APP_ONLINE_DEBUG #define LOG_TAG_CONST ONLINE_DB #define LOG_TAG "[ONLINE_DB]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE /* #define LOG_DUMP_ENABLE */ #define LOG_CLI_ENABLE #include "debug.h" #if 1 #define DB_MEM_BUF_LEN (768 * 15) #else #define DB_MEM_BUF_LEN (768) #endif #define DB_ONE_PACKET_LEN (256) #define DB_PRINT_DATA_EN 0//是否上报串口打印数据 #define DB_PRINT_DELAY_TYPE 0//0-timeout check,1-time check #define DB_PRINT_NOT_SEND_HEAD 0// #define DB_TIMER_SET (200) //unit:ms #define DB_PAYLOAD_MAXSIZE (253) #define DB_TMP_PACKET_LEN (660) #if DB_PRINT_DATA_EN #define DB_PRINT_BUFF_LEN (128) #endif #define cbuf_get_space(a) (a)->total_len enum { DB_EVT_MSG_NULL = 0, DB_EVT_MSG_SEND, }; enum { DB_TO_TYPE_PRINT = 0, }; struct db_head_t { u8 length; u8 type; u8 seq; u8 data[0]; } _GNU_PACKED_; struct db_online_info_t { u16 db_timer; u8 res_byte; u8 seq; int (*send_api)(u8 *packet, u16 size); cbuffer_t send_cbuf; u8 db_mem_buffer[DB_MEM_BUF_LEN]; u8 tmp_send_buf[DB_TMP_PACKET_LEN]; u16 tmp_data_len; u8 tmp_recieve_buf[DB_ONE_PACKET_LEN]; u16 tmp_recieve_len; #if DB_PRINT_DATA_EN u8 print_buffer[DB_PRINT_BUFF_LEN * 2]; volatile u8 *print_buf_prt; volatile u16 print_count; #endif }; static volatile u8 db_send_busy = 0; static volatile u8 db_timeout_type = 0; static volatile u16 print_record_count = 0; static struct db_online_info_t *online_global_info; #define __this (online_global_info) static int db_cb_api_table[DB_PKT_TYPE_MAX]; static volatile u8 db_active = DB_COM_TYPE_NULL; static spinlock_t lock; //----------------------------------------------------- static void db_timeout_handle(int type); //----------------------------------------------------- //获取cbuff 数据 static u16 db_data_read_sub(u8 *buf, u16 buf_size) { u16 ret_len = 0; if (0 == cbuf_get_data_size(&__this->send_cbuf)) { return 0; } spin_lock(&lock); if (cbuf_get_data_size(&__this->send_cbuf)) {//check again cbuf_read(&__this->send_cbuf, &ret_len, 2); if (ret_len && ret_len <= buf_size) { cbuf_read(&__this->send_cbuf, buf, ret_len); } } spin_unlock(&lock); return ret_len; } //尝试发送cbuff 数据 static void db_data_try_send(void) { u16 send_len; if (db_send_busy) { return; } db_send_busy = 1;//hold if (__this->tmp_data_len) { /* log_info("send_tmp_data = %d",__this->tmp_data_len); */ if (__this->send_api) { if (__this->send_api(__this->tmp_send_buf, __this->tmp_data_len)) { db_send_busy = 0;//fail return; } __this->tmp_data_len = 0; } } send_len = db_data_read_sub(__this->tmp_send_buf, DB_TMP_PACKET_LEN); if (send_len > DB_TMP_PACKET_LEN) { ASSERT(send_len <= DB_TMP_PACKET_LEN); } if (send_len) { /* log_info("send_buf_data = %d",send_len); */ if (__this->send_api(__this->tmp_send_buf, send_len)) { __this->tmp_data_len = send_len; db_send_busy = 0;//fail } } else { //not send db_send_busy = 0; } } //写入数据到cbuff static u32 db_data_write_sub(u8 *head, u8 head_size, u8 *data, u16 len) { u16 wlen = 0; u16 total_len = 0; if (!db_active) { /* log_error("not active!"); */ return 0; } ASSERT(len <= DB_ONE_PACKET_LEN); total_len = head_size + len; spin_lock(&lock); u16 buf_space = cbuf_get_space(&__this->send_cbuf) - cbuf_get_data_size(&__this->send_cbuf); if (total_len + 2 > buf_space) { /* log_error("cbuf full!"); */ spin_unlock(&lock); return 0; } wlen = cbuf_write(&__this->send_cbuf, &total_len, 2); if (head_size) { wlen += cbuf_write(&__this->send_cbuf, head, head_size); } if (len) { wlen += cbuf_write(&__this->send_cbuf, data, len); } spin_unlock(&lock); /* db_data_try_send(); */ if (!db_send_busy) { db_data_try_send(); } return wlen; } //处理协议栈来数,分发到已注册模块解析处理 static void db_packet_handle(u8 *packet, u16 size) { if (!db_active) { return; } struct db_head_t *db_ptr = (void *)packet; int ret = -1; if (db_ptr->length == 0) { log_error("len=0"); return; } //判读是否需要缓存组包 if (__this->tmp_recieve_len) { if (__this->tmp_recieve_len + size > DB_ONE_PACKET_LEN) { log_error("rx_len_err:%d", __this->tmp_recieve_len + size); __this->tmp_recieve_len = 0; return; } memcpy(&__this->tmp_recieve_buf[__this->tmp_recieve_len], packet, size); __this->tmp_recieve_len += size; if (__this->tmp_recieve_len < db_ptr->length) { /* putchar('<'); */ return; } db_ptr = (void *)&__this->tmp_recieve_buf; packet = (void *)&__this->tmp_recieve_buf; size = __this->tmp_recieve_len; __this->tmp_recieve_len = 0; /* putchar('>'); */ } else { if (size < db_ptr->length) { __this->tmp_recieve_len = size; memcpy(&__this->tmp_recieve_buf, packet, size); /* putchar('<'); */ return; } } if (db_ptr->type == 0 || db_ptr->type >= DB_PKT_TYPE_MAX) { log_error("type_err"); return; } /* int (*db_parse_data)(u8 *packet,u8 size,u8 *ext_data,ext_size); */ int (*db_parse_data)(u8 * packet, u8 size, u8 * ext_data, u16 ext_size) = (void *)(db_cb_api_table[db_ptr->type]); if (db_parse_data) { /* log_info("db_parse_data,%08x",db_parse_data); */ log_info("rx_data(%d):", size); log_info_hexdump((void *)db_ptr, size); u8 *tmp_buf_pt = malloc(DB_ONE_PACKET_LEN); if (!tmp_buf_pt) { log_error("malloc faill,drop data!!!"); return; } size -= 3; //整理对齐 memcpy(tmp_buf_pt, db_ptr->data, size); db_parse_data(tmp_buf_pt, size, &db_ptr->type, 2); free(tmp_buf_pt); } } //打印数据推送处理,需要临界保护 static void db_print_send_deal(void) { #if DB_PRINT_DATA_EN static volatile u8 send_flag = 0; u16 tmp_len = 0; u8 *tmp_buf; if (send_flag) { __this->print_count = 0;//drop data return; } //乒乓buffer spin_lock(&lock); send_flag = 1; if (__this->print_count) { //check again tmp_len = __this->print_count; tmp_buf = __this->print_buf_prt; if (__this->print_buf_prt == __this->print_buffer) { __this->print_buf_prt = &__this->print_buffer[DB_PRINT_BUFF_LEN]; } else { __this->print_buf_prt = __this->print_buffer; } __this->print_count = 0; } spin_unlock(&lock); if (tmp_len) { app_online_db_send(DB_PKT_TYPE_PRINT, tmp_buf, tmp_len); } send_flag = 0; #endif } //截取串口打印数据处理 static int db_hook_put_byte(char a) { int ret = 0; //0--keep uart,1--not uart #if DB_PRINT_DATA_EN static volatile repeat_cnt = 0; if (!db_active) { return ret; } if (repeat_cnt) { return ret; } repeat_cnt = 1; if (__this->print_count > (DB_PRINT_BUFF_LEN - 4)) { db_print_send_deal(); } __this->print_buf_prt[__this->print_count++] = (u8)a; repeat_cnt = 0; #if (0 == DB_PRINT_DELAY_TYPE) if (0 == (db_timeout_type & BIT(DB_TO_TYPE_PRINT))) { db_timeout_type |= BIT(DB_TO_TYPE_PRINT); print_record_count = __this->print_count; sys_timeout_add(DB_TO_TYPE_PRINT, db_timeout_handle, DB_TIMER_SET); } #endif #endif return ret; } #if (1 == DB_PRINT_DELAY_TYPE) //定义检测打印数据是否需要超时推送到上位机 static void db_print_timer_handle(void) { #if DB_PRINT_DATA_EN if (__this->print_count) { if (print_record_count == __this->print_count) { //第二次检查相同才输出打印 db_print_send_deal(); } else { print_record_count = __this->print_count; } } #endif } #endif //检测打印数据是否需要超时推送到上位机 static void db_timeout_handle(int type) { #if DB_PRINT_DATA_EN #if (0 == DB_PRINT_DELAY_TYPE) if (!db_active) { return; } /* putchar('&'); */ if (type == DB_TO_TYPE_PRINT) { if (__this->print_count) { //第二次检查相同才输出打印 if (print_record_count == __this->print_count) { //第二次检查相同才输出打印 db_timeout_type &= (~BIT(DB_TO_TYPE_PRINT)); db_print_send_deal(); } else { print_record_count = __this->print_count; sys_timeout_add(DB_TO_TYPE_PRINT, db_timeout_handle, DB_TIMER_SET); } } else { db_timeout_type &= (~BIT(DB_TO_TYPE_PRINT)); } } #endif #endif } //上位机连上初始化 static void db_init(db_com_e conn_type) { if (db_active) { return; } log_info("db_init"); if (!__this) { __this = malloc(sizeof(struct db_online_info_t)); if (!__this) { log_error("malloc faill!!!"); return; } } cbuf_init(&__this->send_cbuf, __this->db_mem_buffer, DB_MEM_BUF_LEN); #if(1 == DB_PRINT_DELAY_TYPE) __this->db_timer = sys_timer_add(NULL, db_print_timer_handle, DB_TIMER_SET); #endif __this->tmp_data_len = 0; __this->tmp_recieve_len = 0; db_send_busy = 0; #if DB_PRINT_DATA_EN __this->print_count = 0; __this->print_buf_prt = __this->print_buffer; /* register_putbyte_hook(db_hook_put_byte); */ #endif db_active = conn_type; //db_print_test_function(); /* for (int i = 0; i < 512; i++) { */ /* test_buffer_data22[i] = i; */ /* } */ /* sys_timer_add(0, db_test_send_data, 200); */ /* printf_buf(test_buffer_data22, 512); */ } //上位断开,退出 static void db_exit(void) { if (!db_active) { return; } log_info("db_exit"); db_active = DB_COM_TYPE_NULL; #if (1 == DB_PRINT_DELAY_TYPE) if (__this->db_timer) { sys_timer_del(__this->db_timer); __this->db_timer = 0; } #endif #if DB_PRINT_DATA_EN /* register_putbyte_hook(NULL); */ #endif spin_lock(&lock); cbuf_clear(&__this->send_cbuf); spin_unlock(&lock); free(__this); __this = NULL; } //注册协议栈发送接口 static void db_register_send_data(void *send_api_call) { if (!db_active) { return; } __this->send_api = send_api_call; } //协议栈发送完成,唤醒 static void db_wakeup_send_data(void) { if (!db_active) { return; } db_send_busy = 0;// db_data_try_send(); } static struct db_online_api_t de_online_api_table = { .init = db_init, .exit = db_exit, .packet_handle = db_packet_handle, .register_send_data = db_register_send_data, .send_wake_up = db_wakeup_send_data, }; //获取接口列表 struct db_online_api_t *app_online_get_api_table(void) { return &de_online_api_table; } //注册模块解析函数 void app_online_db_register_handle(db_pkt_e type, int (*db_parse_data)(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)) { if (type == 0 || type >= DB_PKT_TYPE_MAX) { log_error("reg_type_err"); return; } log_info("register_handle %d,%08x", type, db_parse_data); db_cb_api_table[type] = (int)db_parse_data; } //获取可发送数据的长度 int app_online_get_buf_remain(db_pkt_e type) { if (!db_active) { return 0; } int w_len = 0; int head_size = 3; int buf_space = cbuf_get_space(&__this->send_cbuf) - cbuf_get_data_size(&__this->send_cbuf); int pack_size = head_size + DB_PAYLOAD_MAXSIZE; if (buf_space <= head_size) { w_len = 0; } else if (buf_space < pack_size) { w_len = buf_space - head_size; } else { w_len = (buf_space / pack_size) * DB_PAYLOAD_MAXSIZE; buf_space = buf_space % pack_size; if (buf_space > head_size) { w_len += (buf_space - head_size); } } return w_len; } //发送包,发送 int app_online_db_send(db_pkt_e type, u8 *packet, u8 size) { if (!db_active) { return -1; } struct db_head_t db_ptr; db_ptr.length = size + 2; db_ptr.type = type; db_ptr.seq = __this->seq++; u8 head_size = 3; if (!size) { log_error("size err!!!"); return -2; } #if (DB_PRINT_DATA_EN && DB_PRINT_NOT_SEND_HEAD) if (DB_PKT_TYPE_PRINT == type) { head_size = 0;//不发送头 } #endif log_info("tx_data(%d):,type=%d", size, type); log_info_hexdump(packet, size); if (!db_data_write_sub((u8 *)&db_ptr, head_size, packet, size)) { log_error("full fail,%d,%d", type, size); return -3; } return 0; } //发送包,发送 int app_online_db_send_more(db_pkt_e type, u8 *packet, u16 size) { if (!db_active) { return -1; } struct db_head_t db_ptr; u8 head_size = 3; if (!size || size > 650) { log_error("overflow!!!%d,%d", type, size); return -2; } log_info("tx_more_data(%d):,type=%d", size, type); log_info_hexdump(packet, size); u16 need_buff_size = ((size / DB_PAYLOAD_MAXSIZE) * (DB_PAYLOAD_MAXSIZE + head_size)); u16 remain_size = size % DB_PAYLOAD_MAXSIZE; if (remain_size) { need_buff_size += (remain_size + head_size); } spin_lock(&lock); if (need_buff_size + 2 > app_online_get_buf_remain(type)) { spin_unlock(&lock); log_error("more full!!!"); return -3; } u16 payload_size; db_ptr.type = type; cbuf_write(&__this->send_cbuf, &need_buff_size, 2); while (size) { if (size > DB_PAYLOAD_MAXSIZE) { payload_size = DB_PAYLOAD_MAXSIZE; } else { payload_size = size; } size -= payload_size; db_ptr.length = payload_size + 2; db_ptr.seq = __this->seq++; cbuf_write(&__this->send_cbuf, &db_ptr, head_size); cbuf_write(&__this->send_cbuf, packet, payload_size); packet += payload_size; } spin_unlock(&lock); db_data_try_send(); /* if (!db_send_busy) { */ /* db_data_send_msg(DB_EVT_MSG_SEND); */ /* } */ return 0; } //应答包,发送 int app_online_db_ack(u8 seq, u8 *packet, u8 size) { if (!db_active) { return -1; } struct db_head_t db_ptr; db_ptr.length = size + 2; db_ptr.type = DB_PKT_TYPE_ACK; db_ptr.seq = seq; log_info("tx_ack(%d):,seq=%d", size, seq); log_info_hexdump(packet, size); if (!db_data_write_sub((u8 *)&db_ptr, 3, packet, size)) { log_error("send fail2,%d,%d", seq, size); return -1; } return 0; } void app_online_event_handle(int evt_value) { if (!db_active) { return; } if (evt_value == DB_EVT_MSG_SEND) { /* putchar('@'); */ db_data_try_send(); } } void app_online_putchar(char a) { db_hook_put_byte(a); } void app_online_puts(char *str) { while (*str != 0) { db_hook_put_byte(*str++); } } static void app_online_put_u4hex(unsigned char dat) { dat = 0xf & dat; if (dat > 9) { app_online_putchar(dat - 10 + 'A'); } else { app_online_putchar(dat + '0'); } } void app_online_put_u16hex(u16 dat) { app_online_putchar('0'); app_online_putchar('x'); app_online_put_u4hex(dat >> 12); app_online_put_u4hex(dat >> 8); app_online_put_u4hex(dat >> 4); app_online_put_u4hex(dat); app_online_putchar(' '); } void app_online_put_u8hex(u8 dat) { app_online_put_u4hex(dat >> 4); app_online_put_u4hex(dat); app_online_putchar(' '); } void app_online_put_u32hex(u32 dat) { app_online_putchar('0'); app_online_putchar('x'); app_online_put_u4hex(dat >> 28); app_online_put_u4hex(dat >> 24); app_online_put_u4hex(dat >> 20); app_online_put_u4hex(dat >> 16); app_online_put_u4hex(dat >> 12); app_online_put_u4hex(dat >> 8); app_online_put_u4hex(dat >> 4); app_online_put_u4hex(dat); app_online_putchar(' '); } void app_online_put_buf(u8 *buf, u16 len) { for (int i = 0; i < len; i++) { if ((i % 16) == 0) { app_online_putchar('\n') ; } app_online_put_u8hex(buf[i]) ; } app_online_putchar('\n') ; } static const u8 test_buffer_data[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; static void db_print_test_function(void) { app_online_puts("print test start\n"); app_online_putchar('@'); app_online_put_u8hex(0x78); app_online_put_u16hex(0x1234); app_online_put_u32hex(0x33445566); app_online_put_buf((u8 *)test_buffer_data, 32); app_online_puts("print test end\n"); } #endif