#include "stdio.h" #include "rtthread.h" #include "board.h" #include "mystdlib.h" #include "list.h" #include "mystring.h" #include "signal.h" #include "prot_uc.h" #include "buff.h" #include "bytearray.h" #include "debug.h" #include "crc.h" #include "dev_flash.h" #include "mymisc.h" #include "elec_det.h" #include "commend.h" // 接收buff大小 #define RECV_BUFF_SIZE 300 // 最大接收信号个数 #define RECV_SEM_MAX_NUM 10 // 接收数据超时时间 #define RECV_EXPIRE_TIME 100 static void recv_irq(void *t,uint8_t d) { protu_def *p=t; p->buff[p->buff_index]=d; p->buff_index++; switch(p->buff_index){ case 2: if(p->buff[0]==0x59&&p->buff[1]==0x6d) { p->is_big_data=0; p->num_to_recv=4; }else{ p->buff[0]=p->buff[1]; p->num_to_recv=0; } break; case 4: { int len=p->buff[2]|(p->buff[3]<<8); if(len<65535){ p->is_big_data=0; p->num_to_recv+=len+2; }else{ p->is_big_data=1; p->num_to_recv=11; } } break; case 11: { if(p->is_big_data==1) { int len=p->buff[7]|(p->buff[8]<<8)|(p->buff[9]<<16)|(p->buff[10]<<24); p->num_to_recv=4+len+2; } } break; default: break; } // 此时一帧数据已完成 if(p->num_to_recv>0&&p->num_to_recv==p->buff_index) { //DBG_LOG("recv:%s",str_temp(arr_string(p->buff))); rt_sem_release(p->sem); } } static void recv_end_irq(void *t,uint32_t len) { protu_def *p=t; p->num_to_recv=len; p->buff_index=len; p->sem_num++; if(p->sem_numsem); p->recv_tick=rt_tick_get(); } } array_def *protu_decode_str(protu_def *p,array_def *data); array_def *protu_encode_str(protu_def *p,array_def *data); // 查找指定解码器 codec_item *protu_find_codec(const char *name) { extern const int codecstruct$$Base; extern const int codecstruct$$Limit; codec_item *start=(codec_item *)&codecstruct$$Base; codec_item *end=(codec_item *)&codecstruct$$Limit; for(codec_item *t=start;tname,name)==0) { return t; } } return 0; } // 返回正在使用的解码器 codec_item *protu_codec_inuse(protu_def *p) { return p->codec; } void protu_codec_set(protu_def *p,codec_item *c) { p->codec=c; } // 尝试解码 static array_def *protu_try_decode(protu_def *p,array_def *data) { array_def *decode_data=0; if(p->codec==0||p->codec->decode==protu_decode_str|| (decode_data=p->codec->decode(p,data),strcmp(p->str_err,"ok")!=0)) { CHECK_DO(decode_data,arr_delete); #if defined (__CC_ARM) extern const int codecstruct$$Base; extern const int codecstruct$$Limit; codec_item *start=(codec_item *)&codecstruct$$Base; codec_item *end=(codec_item *)&codecstruct$$Limit; #elif defined (__GNUC__) extern const int __start_codecstruct; extern const int __stop_codecstruct; codec_item *start=(codec_item *)&__start_codecstruct; codec_item *end=(codec_item *)&__stop_codecstruct; #endif for(codec_item *t=start;tdecode(p,data); if(strcmp(p->str_err,"ok")==0) { p->codec=t; break; } else{ arr_delete(decode_data); } } } if(decode_data==0) decode_data=arr_creat(); return decode_data; } static void protu_run(void *t) { protu_def *p=t; array_def *data; array_def *decode_data; uint32_t tick_now; while(p->run) { rt_sem_take(p->sem,RT_WAITING_FOREVER); p->sem_num=0; if(p->buff_index==0){ continue; } tick_now=rt_tick_get(); if(tick_now-p->recv_tick>RECV_EXPIRE_TIME){ DBG_LOG("recv data expired."); p->num_to_recv=0; p->buff_index=0; continue; } //DBG_LOG("protu run"); data=arr_creat(); arr_appends(data,p->buff,p->buff_index); p->num_to_recv=0; p->buff_index=0; //DBG_LOG("recv:%s",str_temp(arr_string(data))); decode_data=protu_try_decode(p,data); //DBG_LOG("decode:%s",str_temp(arr_string(decode_data))); if(p->codec) emit protu_recv_signal(p,p->codec->name, p->cmd,arr_temp(decode_data),str_temp(str_duplicate(p->str_err))); arr_delete(data); irq_disable(); p->num_to_recv=0; irq_enable(); } } // 根据设备类型初始化编解码指针 static void protu_set_endecode_fun(protu_def *u) { const sys_param_def *par=sys_param(); if(strcmp(par->device_type,"coder")==0) { } else if(strcmp(par->device_type,"checker")==0) { } } static int protu_init(void) { const sys_param_def *par=sys_param(); const char *name="host"; protu_def *protu=protu_creat(dev_get(name)); app_variable("protu",protu,0); // 复制一个引用,用于命令行调试 app_variable("protu2",protu,0); return 0; } app_init_export(protu_init) protu_def *protu_creat(uart_def *uart) { static uint16_t count=0; char name[20]={0}; protu_def *p=calloc(1,sizeof(protu_def)); param_check(p); p->uart=uart; sprintf(name,"protu_sem#%d",count); p->sem=rt_sem_create(name,0,RT_IPC_FLAG_FIFO); p->buff=malloc(RECV_BUFF_SIZE); p->run=1; p->cmd=0xff;// 命令字不可能是0xff protu_set_endecode_fun(p); sprintf(name,"protu_t#%d",count); rt_thread_t rt_t=rt_thread_create(name,protu_run,p,1024,6,20); rt_thread_startup(rt_t); int bsp=sys_param()->uartbsp; if(bsp==9600) p->uart->init(p->uart,9600); else p->uart->init(p->uart,0); //p->uart->set_irq(p->uart,recv_irq,p); p->uart->set_end_irq(p->uart,p->buff,RECV_BUFF_SIZE,recv_end_irq,p); p->timer=dev_get("timer"); p->timer->init(p->timer); count++; return p; } int protu_send(protu_def *p,array_def *data,int timeout_ms) { //DBG_LOG("send:%s",str_temp(arr_string(data))); return p->uart->write(p->uart,arr_data(data),arr_length(data),timeout_ms); } typedef struct{ protu_def *p; array_def *t; }send_pkt_def; static void protu_send_later(void *ptr) { send_pkt_def *s=ptr; protu_send(s->p,s->t,1000); // arr_delete(s->t); } static send_pkt_def g_send_pkt; // 在指定时间间隙中发送 // 返回0失败 static int protu_send_ontime(protu_def *p,send_pkt_def *s) { uint32_t tick=p->timer->read(p->timer); // 根据返回的数据长度计算发送需要的时间,添加1ms的余量 // 根据协议,每个指令从机的返回数据长度等长,所以需要的时间窗口也相等 // 253字节需要23ms // 每ms传输的字节数为253/23=11, // 考虑can总线自动重传保留1/3的余量 int wnd_tick=((arr_length(s->t)+4)/5+2); int delay=tick%(wnd_tick*(p->num)); int gap=p->rank*wnd_tick; if(delay<=gap){ delay=gap-delay; }else{ delay=gap+(wnd_tick*(p->num))-delay; } if(p->silent!=0){ // 广播命令在指定时间窗口发送 //later_execute(protu_send_later,s,delay); while(p->timer->read(p->timer)<(tick+delay)); // protu_send_later(s); return protu_send(s->p,s->t,wnd_tick-1); }else{ // 单播命令直接发送 protu_send_later(s); return arr_length(s->t); } } static int g_send_failed_times; static int protu_send_ontime_loop(protu_def *p,send_pkt_def *s,int retry) { // g_send_failed_times=0; for(int i=0;it); return 0; } static int send_failed(list_def *argv) { cmd_print("send failed times=%d",g_send_failed_times); return 0; } commend_export(send_failed,send_failed,"print send_failed times") // 槽函数,回复上位机 void protu_reply_call(protu_def *p,array_def *data) { param_check(p); array_def *t=0; if(p->codec) t=p->codec->encode(p,data); // DBG_LOG("send encode:%s",arr_string(t)); if(t){ g_send_pkt.p=p; g_send_pkt.t=t; protu_send_ontime_loop(p,&g_send_pkt,3); } } // 槽函数,主动上发 void protu_send_call(protu_def *p,uint8_t cmd,array_def *data) { array_def *t=0; if(cmd!=0){ p->cmd=cmd; if(p->codec) t=p->codec->encode(p,data); }else if(p->cmd==0) { // 命令字为0是字符串 t=protu_encode_str(p,data); } if(t){ g_send_pkt.p=p; g_send_pkt.t=t; protu_send_ontime_loop(p,&g_send_pkt,3); } } // 字符串解码 array_def *protu_decode_str(protu_def *p,array_def *data) { array_def *r=arr_creat(); param_check(r); DBG_LOG("decode for command"); str_set(p->str_err,"ok"); p->cmd=0; if(str_is_print_str((const char *)arr_data(data),arr_length(data))==1) { p->silent=0; arr_append(data,0); arr_appends_from(r,data); }else{ DBG_WARN("data not a string"); str_set(p->str_err,"not string"); //arr_remove(data,arr_length(data)-1,1); } return r; } // 字符串编码 array_def *protu_encode_str(protu_def *p,array_def *data) { array_def *t=arr_creat(); param_check(t); arr_appends_from(t,data); return t; } protuc_codec_export(string,protu_decode_str,protu_encode_str);