| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675 |
- /******************************************************************************
- 版权所有:
- 文件名称: 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<len; i++)
- {
- sum += *buf++;
- }
- return sum;
- }
- int can_app_timing(void)
- {
- static long g_timing_sec = 0;
-
- int i,ret;
- u8 *buf;
- struct timespec ts;
- clk_time_get(&ts);
-
- // 对时帧必须在内部对时秒脉冲发出10ms后再发送,每秒发送一次。
- if(ts.tv_sec == g_timing_sec || ts.tv_nsec < 10*NSEC_PER_MS)
- {
- return 0;
- }
- // 帧头
- buf = can_request_tx_buf(CAN_FRAME_TYPE_TIMING);
- buf[0] = CAN_FRAME_TYPE_TIMING;
- buf[1] = CAN_BUS_ADDR_BCAST;
- buf[2] = 0;
- buf[3] = sizeof(int); // long -> int 8byte -> 4 byte, 暂时按回4字节传输,待确认 EWen
- // 得到时间
- memcpy(buf+4,&ts.tv_sec,sizeof(int));//noted by sunxi: 这里需要注意大小端问题
-
- // 发送
- for(i=0;i<CAN_BUS_NUM;i++)
- {
- ret = can_send(i,buf);
- if(ret < 0)
- {
- // rt_printf("can_app_timing:ret=%d\r\n",ret);
- }
- }
- g_timing_sec = ts.tv_sec;
-
- return 0;
- }
- int can_app_reset(int is_watchdog)
- {
- int i ;
- u8 *buf;
- // 帧头
- buf = can_request_tx_buf(CAN_FRAME_TYPE_RESET);
- buf[0] = CAN_FRAME_TYPE_RESET;
- buf[1] = CAN_BUS_ADDR_BCAST;
- buf[2] = 0;
- buf[3] = 1;
- buf[4] = (u8)is_watchdog;
- // 发送
- for(i=0;i<CAN_BUS_NUM;i++)
- {
- can_send(i,buf);
- }
- // 子板复位时更新时间,避免产生子板通讯异常错误。
- for(i=0;i<EQU_SLOT_NUM_MAX;i++)
- {
- g_board_info[i].us0 = ustimer_get_origin();
- }
-
- return 0;
- }
- int can_app_sb_monitor(void)
- {
- g_sb_monitor = 1;
-
- return 0;
- }
- int can_app_sb_monitor_send(void)
- {
- u8 buf[4];
-
- buf[0] = CAN_FRAME_TYPE_SB_MONITOR;
- buf[1] = CAN_BUS_ADDR_BCAST;
- buf[2] = 0;
- buf[3] = 0;
- // 发送
- can_send(0,buf);
- can_send(1,buf);
-
- return 0;
- }
- //can子板查询 oujie add 20200420
- int can_app_sb_discover(void)
- {
- u8 buf[4];
- u32 slot;
- #if defined(BSP_DTU3) || defined(BSP_DTU2) || defined(BSP_DTU5)
- slot = equ_get_slot_by_type(BOARD_TYPE_METERING);
- #else
- slot = 1;
- #endif
- if(slot >0)
- {
- 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; i<sizeof(can_brd->chip_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<CAN_BOARD_NUM; i++)
- {
- if(can_board[i].file_have)
- {
- if((memcmp((u8*)can_board[i].chip_id, &buf[5], sizeof(can_board[i].chip_id)) == 0)
- && (can_board[i].slot == buf[4]))
- {
- #ifdef CAN_BOARD_DEBUG
- rt_printf("分配子板号完成\r\n");
- #endif
- can_board[i].given_slot = 1;
- }
- }
- }
- #else
- if((memcmp((u8*)can_board[0].chip_id, &buf[5], sizeof(can_board[0].chip_id)) == 0)
- && (can_board[0].slot == buf[4]))
- {
- #ifdef CAN_BOARD_DEBUG
- rt_printf("分配子板号完成\r\n");
- #endif
- can_board[0].given_slot = 1;
- }
- #endif
- return 0;
- }
- int errcount_crc=0;
- int errcount_sb=0;
- int errcount_no=0;
- int errcount_sb_no=0;
- int errcount_check=0;
- static u32 g_no_send[CAN_BUS_NUM];
- static u32 g_no_recv[EQU_SLOT_NUM_MAX];
- int can_app_test_send(void)
- {
- u8 *buf_tx;
- int i,can,no,len,ret;
-
- len = 200;
- buf_tx = can_request_tx_buf(CAN_FRAME_TYPE_TEST);
- for(can=0;can<CAN_BUS_NUM;can++)
- {
- no = g_no_send[can];
- buf_tx[0] = CAN_FRAME_TYPE_TEST;
- buf_tx[1] = CAN_BUS_ADDR_BCAST;
- buf_tx[2] = 0;
- buf_tx[3] = len;
-
- buf_tx[4] = 0;
- buf_tx[5] = no;
- buf_tx[6] = no>>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<CAN_BUS_NUM;i++)
- {
- rt_printf("slot%02d:%d.\r\n",i,g_no_send[i]);
- }
-
- rt_printf("g_no_recv:\r\n");
- for(i=0;i<EQU_SLOT_NUM_MAX;i++)
- {
- rt_printf("slot%02d:%d.\r\n",i,g_no_recv[i]);
- }
- return 0;
- }
- #endif
- /*------------------------------ 内部函数 -------------------------------------
- 内部函数以下划线‘_’开头,不需要检查参数的合法性.
- */
- /*------------------------------ 测试函数 -------------------------------------
- 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中
- 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数).
- */
- /*------------------------------ 文件结束 -------------------------------------
- */
|