#include "stdio.h" #include "rtthread.h" #include "board.h" #include "mystdlib.h" #include "list.h" #include "mystring.h" #include "signal.h" #include "handle.h" #include "buff.h" #include "bytearray.h" #include "debug.h" #include "crc.h" #include "prot_mcu.h" #include "mymisc.h" /** * * 批检仪 * BUS1(UART5)->slave 1,2,3,4 * BUS2(UART2)->slave 5,6,7,8 * BUS3(UART3)->slave 9,10,11,12 * BUS4(UART6)->slave 13,14,15,16 * BUS5(UART1)->slave 17,18,19,20 * * 注码仪 * UART5->1,2,3,4 * UART2->5,6,7,8 * UAER3->9,10 * **/ #define PORT_MUN 5 typedef struct{ int init; protm_def *protm[PORT_MUN]; }self_def; static self_def g_self; typedef struct _port_mcu{ protm_def *protm; rt_timer_t timer; int busy; uint8_t addr; handle_def *handle; }port_mcu; int port_init(void) { self_def *s=&g_self; if(s->init==0){ s->protm[0]=protm_creat(dev_get("uart5"),(int []){1,2,3,4},4); s->protm[1]=protm_creat(dev_get("uart2"),(int []){5,6,7,8},4); s->protm[2]=protm_creat(dev_get("uart3"),(int []){9,10,11,12},4); s->protm[3]=protm_creat(dev_get("uart6"),(int []){13,14,15,16},4); s->protm[4]=protm_creat(dev_get("uart1"),(int []){17,18,19,20},4); s->init=1; } return 0; } port_mcu *port_creat(uint8_t addr,sig_thread t) { self_def *s=&g_self; if(s->init==0){ DBG_WARN("port not init."); return 0; } port_mcu *p=calloc(1,sizeof(port_mcu)); param_check(p); p->addr=addr; for(int i=0;iprotm[i],addr)) { p->protm=s->protm[i]; connect(p,port_send_signal,t,p->protm,protm_send_call); connect(p->protm,protm_recv_signal,t,p,port_recv_call); break; } } return p; } void port_delete(port_mcu **p) { param_check(p); param_check(*p); disconnect_sig(*p); CHECK_DO((*p)->timer,rt_timer_delete); CHECK_DO((*p)->handle,(*p)->handle->del); free(*p); *p=0; } void port_recv_call(port_mcu *obj,uint8_t src,uint8_t cmd,array_def *data,char *err_str) { port_mcu *p=obj; if(src==p->addr) { //DBG_LOG("addr=%d,cmd=%d,data=%s.",src,cmd,str_temp(arr_string(data))); if(p->handle){ p->handle->dolater(p->handle,src,cmd,data,err_str); } else{ emit port_end_signal(obj,obj,0,0,"success"); } } // else{ // DBG_WARN("err data,addr=%d.",src); // } } static void port_timeout_cb(void *t) { port_mcu *p=t; if(p->handle) p->handle->timeout(p->handle); } // 开始定时器,重复调用会重新开始 void port_timer_start(port_mcu *p) { param_check(p); CHECK_DO(p->timer,rt_timer_start); } // 停止定时器 void port_timer_stop(port_mcu *p) { param_check(p); CHECK_DO(p->timer,rt_timer_stop); } // 设置忙状态 void port_set_busy(port_mcu *p,int busy) { param_check(p); p->busy=busy?1:0; } // 获取忙状态 int port_get_busy(port_mcu *p) { param_check(p); return p->busy; } // 获取通信地址 uint8_t port_get_addr(port_mcu *p) { return p->addr; } // 开始一个通信操作,h是此项操作的类 int port_start(port_mcu *p,handle_def *h) { param_check(p); param_check(h); if(port_get_busy(p)==1){ h->del(h); DBG_WARN("slave:%d, handle is busy:%s",p->addr, p->handle->name); return -1; } CHECK_DO(p->handle,p->handle->del); p->handle=h; p->handle->p=p; if(p->timer==0) { char s1[16]={0}; sprintf(s1,"port_t#%d",p->addr); p->timer=rt_timer_create(s1,port_timeout_cb,p, rt_tick_from_millisecond(h->interval), RT_TIMER_FLAG_PERIODIC|RT_TIMER_FLAG_SOFT_TIMER); } else{ rt_tick_t tick=rt_tick_from_millisecond(h->interval); rt_timer_control(p->timer,RT_TIMER_CTRL_SET_TIME,&tick); } rt_timer_start(p->timer); p->handle->start(p->handle); return 0; } #define MCU_APP_ADDR_BASE 0x8002400 #define MCU_TASKID_ADDR_BASE 0x800f400 typedef struct{ handle_def h; const uint8_t *data;// 外部地址指针,不需要释放 int size; int stat; int sent; int retry_time;//升级失败重试次数 rt_timer_t timer;// 用于发送命令超时 }updata_def; static void updata_del(handle_def *h) { updata_def *c=(updata_def *)h; CHECK_DO(c->timer,rt_timer_delete); free(h); } static void updata_start(handle_def *h) { updata_def *c=(updata_def *)h; port_set_busy(h->p,1); c->stat=1; c->sent=0; list_def *l=list_creat_int(); int arr[]={0xf9}; list_appends(l,arr,1); emit port_send_signal(h->p,((port_mcu *)h->p)->addr,0xf9,list_temp(l),arr_temp(arr_creat()),60,1); } // 跳转到bootloader之后,需要延时一段时间发送擦除命令 static void updata_earse(void *t) { handle_def *h=t; list_def *l=list_creat_int(); int arr[]={0xfe}; list_appends(l,arr,1); emit port_send_signal(h->p,((port_mcu *)h->p)->addr,0xfe,list_temp(l),arr_temp(arr_creat()),5500,1); } static void updata_dolater(handle_def *h,uint8_t src,uint8_t cmd,array_def *data,char *err_str) { updata_def *c=(updata_def *)h; if(port_get_busy(h->p)==0) return; port_timer_start(h->p); if(c->stat==1){ if((arr_length(data)>=2)&&(1==arr_get(data,1))) { // 这是重试的流程,如果重试时在app状态,则升级成功 if(c->retry_time>0){ DBG_LOG("slave:%d mcu updata success.",src); emit port_end_signal(h->p,h->p,0,0,"ok"); port_set_busy(h->p,0); port_timer_stop(h->p); return ; } // 如果设备不在bootloader,进入这一步 c->stat=2; DBG_LOG("slave:%d mcu in app mode.",src); // 设备跳转后不响应此命令,只重发一次 list_def *l=list_creat_int(); int arr[]={0xf8}; list_appends(l,arr,1); emit port_send_signal(h->p,((port_mcu *)h->p)->addr,0xf8,list_temp(l),arr_temp(arr_creat()),60,3); }else{ // 都在bootloader模式,直接进入下一步 c->stat=3; DBG_LOG("slave:%d mcu in bootloader mode.",src); updata_earse(h); } }else if(c->stat==2){ c->stat=3; DBG_LOG("slave:%d mcu turn in bootloader mode.",src); later_execute(updata_earse,h,1000); }else if(c->stat==3){ if(c->sentsize) { int len=c->sentsize-240?240:c->size-c->sent; uint32_t addr=MCU_APP_ADDR_BASE+c->sent; array_def *temp=arr_creat(); arr_append(temp,addr&0xff); arr_append(temp,(addr>>8)&0xff); arr_append(temp,(addr>>16)&0xff); arr_append(temp,(addr>>24)&0xff); arr_appends(temp,&c->data[c->sent],len); c->sent+=len; list_def *l=list_creat_int(); int arr[]={0xfc}; list_appends(l,arr,1); emit port_send_signal(h->p,((port_mcu *)h->p)->addr,0xfc,list_temp(l),arr_temp(temp),350,10); //DBG_LOG("slave addr=%d,rate=%d.",h->p->addr,c->sent*100/c->size); }else{ c->stat=4; uint32_t addr; array_def *temp=arr_creat(); addr=MCU_APP_ADDR_BASE; arr_append(temp,addr&0xff); arr_append(temp,(addr>>8)&0xff); arr_append(temp,(addr>>16)&0xff); arr_append(temp,(addr>>24)&0xff); addr=MCU_APP_ADDR_BASE+c->size; arr_append(temp,addr&0xff); arr_append(temp,(addr>>8)&0xff); arr_append(temp,(addr>>16)&0xff); arr_append(temp,(addr>>24)&0xff); uint32_t crc=crc_crc32(c->data,c->size); arr_append(temp,crc&0xff); arr_append(temp,(crc>>8)&0xff); arr_append(temp,(crc>>16)&0xff); arr_append(temp,(crc>>24)&0xff); //DBG_LOG("updata:crc=%08x",crc); list_def *l=list_creat_int(); int arr[]={0xfb}; list_appends(l,arr,1); emit port_send_signal(h->p,((port_mcu *)h->p)->addr,0xfb,list_temp(l),arr_temp(temp),350,10); DBG_LOG("slave:%d file updata done.",src); } } else if(c->stat==4) { DBG_LOG("slave:%d mcu reboot to app.",src); emit port_end_signal(h->p,h->p,0,0,"ok"); port_set_busy(h->p,0); port_timer_stop(h->p); } } static void updata_timeout(handle_def *h) { updata_def *c=(updata_def *)h; // 从机没有指定数目时从这里返回 DBG_WARN("slave:%d,%s timeout.",h->p->addr, h->name); if(c->retry_time>3) { port_timer_stop(h->p); port_set_busy(h->p,0); DBG_WARN("slave:%d,%s failed.",h->p->addr, h->name); emit port_end_signal(h->p,h->p,0,-1,"timeout"); }else{ port_timer_start(h->p); DBG_LOG("slave:%d, updata retry",h->p->addr); h->start(h); c->retry_time++; } } handle_def *updata_creat(const uint8_t *data,int size) { updata_def *c=calloc(1,sizeof(updata_def)); handle_def *h=(handle_def *)c; param_check(h); h->static_=0;// 动态内存这项设置为0 h->start=updata_start; h->dolater=updata_dolater; h->del=updata_del; h->timeout=updata_timeout; h->interval=15000;// 此项根据方案调整 h->name="updata"; c->data=data; c->size=size; return h; } typedef struct{ handle_def h; const uint8_t *data;// 外部地址指针,不需要释放 int size; int stat; int sent; int retry_time;//升级失败重试次数 rt_timer_t timer;// 用于发送命令超时 }updata_scheme_def; static void updata_scheme_del(handle_def *h) { updata_scheme_def *c=(updata_scheme_def *)h; CHECK_DO(c->timer,rt_timer_delete); free(h); } static void updata_scheme_send_packet(handle_def *h) { updata_scheme_def *c=(updata_scheme_def *)h; if(port_get_busy(h->p)==0) return; port_timer_start(h->p); if(c->stat==1){ if(c->sentsize) { int len=c->sentsize-240?240:c->size-c->sent; uint32_t addr=MCU_TASKID_ADDR_BASE+c->sent; array_def *temp=arr_creat(); arr_append(temp,addr&0xff); arr_append(temp,(addr>>8)&0xff); arr_append(temp,(addr>>16)&0xff); arr_append(temp,(addr>>24)&0xff); arr_appends(temp,&c->data[c->sent],len); c->sent+=len; list_def *l=list_creat_int(); int arr[]={0x11}; list_appends(l,arr,1); emit port_send_signal(h->p,((port_mcu *)h->p)->addr,0x11,list_temp(l),arr_temp(temp),350,10); //DBG_LOG("slave addr=%d,rate=%d.",h->p->addr,c->sent*100/c->size); }else{ c->stat=0; uint32_t addr; array_def *temp=arr_creat(); list_def *l=list_creat_int(); int arr[]={0x15}; list_appends(l,arr,1); emit port_send_signal(h->p,((port_mcu *)h->p)->addr,0x15,list_temp(l),arr_temp(temp),350,10); DBG_LOG("slave:%d mcu reboot .",h->p->addr); emit port_end_signal(h->p,h->p,0,0,"ok"); port_set_busy(h->p,0); port_timer_stop(h->p); } } } static void updata_scheme_dolater(handle_def *h,uint8_t src,uint8_t cmd,array_def *data,char *err_str) { updata_scheme_send_packet(h); } static void updata_scheme_start(handle_def *h) { updata_scheme_def *c=(updata_scheme_def *)h; port_set_busy(h->p,1); c->stat=1; c->sent=0; updata_scheme_send_packet(h); } static void updata_scheme_timeout(handle_def *h) { updata_scheme_def *c=(updata_scheme_def *)h; // 从机没有指定数目时从这里返回 DBG_WARN("slave:%d,%s timeout.",h->p->addr, h->name); if(c->retry_time>3) { port_timer_stop(h->p); port_set_busy(h->p,0); DBG_WARN("slave:%d,%s failed.",h->p->addr, h->name); emit port_end_signal(h->p,h->p,0,-1,"timeout"); }else{ port_timer_start(h->p); DBG_LOG("slave:%d, updata retry",h->p->addr); h->start(h); c->retry_time++; } } handle_def *updata_scheme_creat(const uint8_t *data,int size) { updata_scheme_def *c=calloc(1,sizeof(updata_scheme_def)); handle_def *h=(handle_def *)c; param_check(h); h->static_=0;// 动态内存这项设置为0 h->start=updata_scheme_start; h->dolater=updata_scheme_dolater; h->del=updata_scheme_del; h->timeout=updata_scheme_timeout; h->interval=15000;// 此项根据方案调整 h->name="updata_scheme"; c->data=data; c->size=size; return h; } typedef struct{ handle_def h; int data_length; uint8_t cmd; uint8_t data[0]; }usercmd_def; static void usercmd_start(handle_def *h) { usercmd_def *u=(usercmd_def *)h; port_set_busy(h->p,1); list_def *l=list_creat_int(); int arr[]={u->cmd}; list_appends(l,arr,1); emit port_send_signal(h->p,port_get_addr(h->p),u->cmd,list_temp(l),arr_temp(arr_creat()),300,3); } static void usercmd_dolater(handle_def *h,uint8_t src,uint8_t cmd,array_def *data,char *err_str) { usercmd_def *c=(usercmd_def *)h; if(port_get_busy(h->p)==0) return; if(cmd==c->cmd) { port_set_busy(h->p,0); port_timer_stop(h->p); DBG_LOG("slave:%d, userdata:%s",src,str_temp(arr_string(data))); // 直接返回原始数据 emit port_end_signal(h->p,h->p,data,0,"ok"); }else { port_set_busy(h->p,0); port_timer_stop(h->p); DBG_WARN("slave:%d,get usercmd err,%s",src,str_temp(arr_string(data))); emit port_end_signal(h->p,h->p,0,-1,"get usercmd err"); } } static void usercmd_timeout(handle_def *h) { // 从机没有指定数目时从这里返回 port_timer_stop(h->p); port_set_busy(h->p,0); DBG_WARN("slave:%d,%s timeout.",port_get_addr(h->p), h->name); emit port_end_signal(h->p,h->p,0,-1,"timeout"); } static void usercmd_del(handle_def *h) { usercmd_def *c=(usercmd_def *)h; free(h); } handle_def *usercmd_creat(uint8_t cmd,array_def *data) { int data_len=arr_length(data); usercmd_def *c=calloc(1,sizeof(usercmd_def)+data_len); c->cmd=cmd; c->data_length=data_len; for(int i=0;idata[i]=arr_get(data,i);} handle_def *h=(handle_def *)c; param_check(h); h->static_=0;// 动态内存这项设置为0 h->start=usercmd_start; h->dolater=usercmd_dolater; h->del=usercmd_del; h->timeout=usercmd_timeout; h->interval=5000; h->name="usercmd"; return h; }