/****************************************************************************** 版权所有: 文件名称: can_app.c 文件版本: 01.01 创建作者: sunxi 创建日期: 2013-02-28 功能说明: can传输应用层 其它说明: 修改记录: */ /*------------------------------- 头文件 -------------------------------------- */ #include "head.h" #ifdef BSP_CAN_ENABLE /*------------------------------- 宏定义 -------------------------------------- */ /*------------------------------ 类型结构 ------------------------------------- */ /*------------------------------ 全局变量 ------------------------------------- */ int g_sb_monitor; /*------------------------------ 函数声明 ------------------------------------- */ int can_app_callback(u32 can_bus,u8 * buf); /*------------------------------ 外部函数 ------------------------------------- 外部函数供其它实体文件引用,必须仔细检查传入参数的合法性. */ int can_app_init(void) { can_regester_recv_callback(can_app_callback); return 0; } int can_app_exit(void) { can_regester_recv_callback(NULL); return 0; } int can_app_callback(u32 can_bus,u8 * buf) { struct can_frame_head *cfh; // 检查参数 if(can_bus >= CAN_BUS_NUM) { return -1; } if(buf == NULL) { return -2; } cfh = (struct can_frame_head *)buf; switch(cfh->type) { case CAN_FRAME_TYPE_DI_INIT: case CAN_FRAME_TYPE_DI_ON: case CAN_FRAME_TYPE_DI_OFF: case CAN_FRAME_TYPE_DI_INIT1: case CAN_FRAME_TYPE_DI_ON1: case CAN_FRAME_TYPE_DI_OFF1: case CAN_FRAME_TYPE_DI_INIT2: case CAN_FRAME_TYPE_DI_ON2: case CAN_FRAME_TYPE_DI_OFF2: #if defined(BSP_DTU3) || defined(BSP_DTU2) || defined(BSP_DTU5) dido_di_update(buf); #endif break; case CAN_FRAME_TYPE_SB_INFO: #if defined(BSP_DTU3) || defined(BSP_DTU2) || defined(CAN_SLAVE_BOARD) || defined(BSP_DTU5) equ_board_info_update(can_bus,buf); #endif break; default: return 0; break; } return 1; } u8 can_app_checksum(u8 *buf,u8 len) { u8 i,sum; sum = 0; for(i=0; i int 8byte -> 4 byte, 暂时按回4字节传输,待确认 EWen // 得到时间 memcpy(buf+4,&ts.tv_sec,sizeof(int));//noted by sunxi: 这里需要注意大小端问题 // 发送 for(i=0;i0) { buf[0] = CAN_FRAME_TYPE_DISCOVER; buf[1] = CAN_BUS_ADDR_BCAST; buf[2] = 0; buf[3] = 0; #ifdef CAN_BOARD_DEBUG rt_printf("查询子板\r\n"); #endif // 发送 can_send(0,buf); //can_send(1,buf); } return 0; } #if 1 //分配can子板卡槽号 oujie add 20200420 int can_app_sb_give_slot(u32 no, u8* buf) { u8 send_buf[32]; char id_string[64] = {0}; struct can_board_res* can_brd; Hex2Str(&buf[5], id_string, CHIP_ID_SIZE*4); #ifdef CAN_BOARD_DEBUG rt_printf("子板id字符串 = %s\r\n", id_string); rt_printf("获取卡槽号\r\n"); #endif can_brd = equ_get_can_slot(buf[4], buf[5], &buf[6], sizeof(can_brd->chip_id)); if(can_brd != NULL) { can_brd->type = buf[5]; send_buf[0] = CAN_FRAME_TYPE_GIVE_CAN_SLOT; send_buf[1] = CAN_BUS_ADDR_BCAST; send_buf[2] = 0; send_buf[3] = sizeof(can_brd->chip_id)+1; send_buf[4] = can_brd->slot; memcpy(&send_buf[5], can_brd->chip_id, sizeof(can_brd->chip_id)); #ifdef CAN_BOARD_DEBUG rt_printf("CAN发送卡槽号 slot = %d\r\n", can_brd->slot); rt_printf("CAN卡类型 type = %d\r\n", can_brd->type); #endif // 发送 can_send(no, send_buf); } else { #ifdef CAN_BOARD_DEBUG rt_printf("卡槽号已存在,不再发送\r\n"); #endif } return 0; } #endif struct sb_monitor { // 系统 u32 slot; u32 type; u32 start_sec; //中断时间 u32 us_gps_min; u32 us_gps_max; u32 us_100us_min; u32 us_100us_max; u32 us_can_min; u32 us_can_max; // 开出 u32 do_delay_min; u32 do_delay_max; // CAN总线 u32 can_rx_dropped; u32 can_tx_dropped; u32 can_hw_bus_errors; u32 can_hw_errors; u32 can_hw_overrun; u32 can_overrun; }; extern struct rt_stat g_stat_do_delay; int can_app_sb_monitor_recv(u8 * buf) { struct sb_monitor sm; struct timespec ts; memcpy(&sm,&buf[4],sizeof(sm)); rt_printf("\r\n子板监视信息[slot=%02d,type=%02d]:\r\n",sm.slot,sm.type); ts.tv_sec = sm.start_sec; ts.tv_nsec = 0; rt_printf("上电时间: "); rt_printf_time2(ts); rt_printf(" GPS中断时间:\tmin=%d,\tmax=%d\r\n",sm.us_gps_min,sm.us_gps_max); rt_printf("100us中断时间:\tmin=%d,\tmax=%d\r\n",sm.us_100us_min,sm.us_100us_max); rt_printf(" CAN中断时间:\tmin=%d,\tmax=%d\r\n",sm.us_can_min,sm.us_can_max); rt_printf(" 开出延时时间:\tmin=%d,\tmax=%d\r\n",sm.do_delay_min,sm.do_delay_max); rt_stat_in(&g_stat_do_delay,sm.do_delay_max); rt_printf("CAN总线接收丢包:%d\r\n",sm.can_rx_dropped); rt_printf("CAN总线发送丢包:%d\r\n",sm.can_tx_dropped); rt_printf("CAN总线总线错误:%d\r\n",sm.can_hw_bus_errors); rt_printf("CAN总线硬件错误:%d\r\n",sm.can_hw_errors); rt_printf("CAN总线硬件溢出:%d\r\n",sm.can_hw_overrun); rt_printf("CAN总线接收溢出:%d\r\n",sm.can_overrun); return 0; } int can_app_sb_discover_recv(u8 * buf) { struct can_board_res* can_brd; #ifdef CAN_BOARD_DEBUG uint8_t i; #endif #if !defined(BSP_DTU3) || !defined(BSP_DTU2) || !defined(BSP_DTU5) memcpy((u8*)can_board[0].chip_id, &buf[6], sizeof(can_brd->chip_id)); #endif #ifdef CAN_BOARD_DEBUG rt_printf("\r\n接收到子板chip_id: "); for(i=0; ichip_id); i++) { rt_printf("%x ", buf[6+i]); } rt_printf("\r\n"); #endif return 0; } int can_app_sb_slot_recv(u8 * buf) { #ifdef CAN_BOARD_DEBUG rt_printf("接收到子板分配卡槽的应答\r\n"); #endif // TODO EWen 需确认此函数作用 #if defined(BSP_DTU3) || defined(BSP_DTU2) || defined(BSP_DTU5) uint8_t i; for(i=0; i>8; buf_tx[7] = no>>16; buf_tx[8] = no>>24; for(i=0;i<(len-6);i++) { buf_tx[i+9] = i; } buf_tx[len+3] = can_app_checksum(buf_tx+4,len-1); // 发送 ret = can_send(can,buf_tx); if(ret < 0) { if(ret != -7) { rt_printf("can_app_test error:ret=%d\r\n",ret); } } else { g_no_send[can]++; } } return 0; } int can_app_test_recv(u8 * buf) { u8 len,crc,crc_check; int i,no,slot; slot = buf[2]; len = buf[3]; crc = buf[len+3]; crc_check = can_app_checksum(buf+4,len-1); no = buf[5] | ((int)buf[6])<<8 | ((int)buf[7])<<16 | ((int)buf[8])<<24; // 检查CRC if(crc != crc_check) { errcount_crc++; rt_printf("can_app_test_recv:crc error!slot=%d,type=%d,no=%d, crc=%x,crc_check=%x,errcount_crc=%d\r\n",slot,buf[4],no,crc,crc_check,errcount_crc); print_msg("RX_CAN:",buf,buf[3] + 4); return -1; } // 检查子板接收错误 if(buf[4] != 0) { errcount_sb++; rt_printf("can_app_test_recv:sb error! slot=%d,type=%d,no=%d, errcount_sb=%d\r\n",slot,buf[4],no,errcount_sb); print_msg("RX_CAN:",buf,buf[3] + 4); return -2; } // 检查内容 for(i=0;i<(len-6);i++) { if(buf[i+9] != i) { break; } } if(i != (len-6)) { errcount_check++; rt_printf("can_app_test_recv:content error!slot=%d,no=%d,errcount_check=%d\r\n",slot,no,errcount_check); print_msg("RX_CAN:",buf,buf[3] + 4); return -4; } // 检查序号 if(no != g_no_recv[slot]) { errcount_sb_no++; rt_printf("can_app_test_recv:no error!slot=%d,no=%d,g_no_recv[slot]=%d,errcount_sb_no=%d\r\n",slot,no,g_no_recv[slot],errcount_sb_no); print_msg("RX_CAN:",buf,buf[3] + 4); return -5; } // 检查ok,序号加一 g_no_recv[slot]++; return 0; } int can_task(void) { int i; u8 * buf; struct can_frame_head *cfh; static unsigned char send_discover = 0; #ifdef CAN_SLAVE_BOARD static unsigned long us0 = 0; static unsigned long us1 = 0; static unsigned char send_discover = 0; #endif // static unsigned long us1 = 0; u8 can_no = 0; if(g_sb_monitor) { can_app_sb_monitor_send(); g_sb_monitor = 0; } buf = can_request_tx_buf(CAN_FRAME_TYPE_PROGRAM_UPDATE); // 最多一次接收8帧 for(i=0; i<128; i++) { if(can_recv(0,buf,CAN_FRAME_LEN_MAX) <= 0) { if(can_recv(1,buf,CAN_FRAME_LEN_MAX) <= 0) { prog_recv_timeout(); break; } else can_no = 1; } else can_no = 0; // 检查帧内容 cfh = (struct can_frame_head *)buf; #if 0 if(cfh->src >= EQU_SLOT_NUM_MAX) { continue; } #endif if(cfh->src >= (EQU_SLOT_NUM_MAX+CAN_BOARD_NUM)) { continue; } // 处理不同类型的帧 switch(cfh->type) { case CAN_FRAME_TYPE_PROGRAM_UPDATE: prog_recv(buf); break; case CAN_FRAME_TYPE_SB_MONITOR: can_app_sb_monitor_recv(buf); break; case CAN_FRAME_TYPE_TEST: if(can_app_test_recv(buf) != 0) { g_test_on = 0; g_print_can = 0; } break; case CAN_FRAME_TYPE_DISCOVER: can_app_sb_discover_recv(buf); can_app_sb_give_slot(can_no, buf); send_discover = 0; can_brd_error_clear(buf[4]); break; case CAN_FRAME_TYPE_GIVE_CAN_SLOT: //收到子板应答 can_app_sb_slot_recv(buf); break; default: break; } } // 子板程序更新发送 prog_send(); #ifdef CAN_SLAVE_BOARD if(!is_prog_down()) { if(us0 == 0) us0 = ustimer_get_origin(); if(ustimer_delay_origin2(&us0, 3*USTIMER_SEC)) { us0 = 0; can_app_sb_discover(); send_discover++; us1 = ustimer_get_origin(); } if(send_discover>=2) { if(ustimer_delay_origin2(&us1, 2*USTIMER_SEC)) { send_discover = 0; us1 = ustimer_get_origin(); can_brd_error_set(); // rt_printf("can_brd_error_set\r\n"); } } } #endif #if defined(METERING_ENERGY) && defined(CAN_SLAVE_BOARD) if(!is_prog_down()&&!send_discover) can_metering_send_app(); #endif if(g_test_on) { // can_app_test_send(); } return 0; } int can_app_test_printf(void) { int i; for(i=0;i