#include "gprs.h" #include "string.h" #include "port.h" #include "task.h" #include #include #include "EEPROM.h" #include "crc.h" #define TT15 10 #define TT35 100 #define MAX_PACK_LEN 1029 #define MAX_BUF_RX 1280 #define MAX_BUF_TX 20 //////////////////////////// #define PACKHEADLEN 3 //////////////////////////// #define MODEM_SOH 1 //start of header #define MODEM_STX 2 //start of text #define MODEM_ETX 3 //end of text #define MODEM_EOT 4 //end of transmission #define MODEM_ACK 6 //ACK #define MODEM_NAK 21 //NACK 0x15 #define MODEM_ETB 23 //end of trans block #define MODEM_CAN 24 //CANCEL #define MODEM_C 0x43 // //////////////////////////////////////////////////////// enum BKP_CMD{BKP_RESET,BKP_RUN,BKP_IAP,BKP_COPY_APP}; //BKP_IAP 进入IAP模式,如果下载失败退出IAP模式,重启进入运行APP模式 //BKP_COPY 进入拷贝APP模式,拷贝完成写入校验值(CRC)进入BKP_RUN模式 //BKP_RUN 先检查CRC校验值选择直接运行APP,还是BKP_COPY模式,如果拷贝模式校验值不对,进入BKP_IAP模式 #define MODEM_MAX_RETRIES 50 //接收等待延时时间 #define MODEM_CRC_RETRIES 51 //>MODEM_MAX_RETRIES固定为CRC校验 #define MODEM_CAN_COUNT 3 //Wait for 3 times CAN before quiting #define MODEM_EOT_COUNT 1 /////////////////////////////////////////////////////// static uint16_t receCount = 0; //接收到的字节个数 static uint8_t receTimeOut = 0; //接收超时 static uint8_t sendBuf[MAX_BUF_TX] = ""; static uint8_t receBuf[MAX_BUF_RX] = ""; //发送接收缓冲区 static struct pt Pt_rcv= {0}; static union{ char commState; struct{ char beenSend:1; char beenReceived:1; char bCRCOK:1; }bitstate; }CommState; //平时周期性检查从机状态 //发送命令时 #define beenSend CommState.bitstate.beenSend #define beenReceived CommState.bitstate.beenReceived #define bCRCOK CommState.bitstate.bCRCOK #define commState CommState.commState enum MODEM_TYPE{X_MODEM=1,Y_MODEM=2}; typedef struct{ uint8_t nxt_num; //下一数据块序号 uint8_t cur_num; //当块序号 uint8_t EOT; //文件接受完成 int rec_err; //数据块接收状态 unsigned char buf[SECTOR_SIZE]; //数据 uint32_t FlashAddr ; //接收数据的首地址; int FileLength ; //文件长度 int DataLenPerPack ; //每个包的数据长度 int willbeSavePackCnt ; //将要保存的数据包个数,当满一页后清0 uint8_t *cachePtr ; unsigned int filelen; //Ymodem可有带文件名称和长度 char filename[64]; }modem_struct; modem_struct Ymodem = {0}; int InitYModemHeader(modem_struct *mblock,uint8_t* buff,int32_t len); int putc(int c , FILE * stream) { //while(USART_GetITStatus(USART1, USART_IT_TC) != RESET) while (!(USART1->SR & USART_FLAG_TXE)) { __NOP(); }; USART1->DR = c; return c; } void Send2(char c) { receTimeOut = 0; beenReceived =0; receCount = 0; putchar(c); } void Send(char *Buf,int len) { int i = 0; receTimeOut = 0; beenReceived =0; for(i=0;iDR = sendBuf[sendPosi]; //sendBuf[sendPosi]; sendPosi++; } else { USART_ITConfig(USART1, USART_IT_TXE, DISABLE); USART_ITConfig(USART1, USART_IT_TC, ENABLE); } } if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) { USART_ITConfig(USART1, USART_IT_TC, DISABLE); beenSend = 1; //发送完成标志 __NOP(); } */ if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { receTimeOut = TT15; //通讯超时值 if(receCountDR; __NOP(); } else { receBuf[0] = USART1->DR; receCount = 0; __NOP(); } } } void InitUART1(void) { USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //端口初始化 // Configure USART2 Tx as alternate function open-drain GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); //串口初始化 USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//; USART_InitStructure.USART_Mode = USART_Mode_Rx| USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //DMA完成.错误中断 NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_Init(&NVIC_InitStructure); //USART_ITConfig(USART2,USART_IT_TXE, ENABLE); //USART_ITConfig(USART2,USART_IT_TC, ENABLE); USART_ITConfig(USART1,USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE); } PT_THREAD(Thread_ZMODEM(struct pt *pt1)); void InitGPRSConnect(void) { struct pt ptBlink = {0}; InitUART1(); AddTask(TASK_GPRS,TASK_MODE_PERIOD,Thread_ZMODEM,ptBlink,2) ; __NOP(); } void EnterMode(void) { uint16_t cmd = ReadBKP(); switch(cmd) { case BKP_RESET: { //冷启动 //BKP_RUN 先检查CRC校验值正确与否 选择直接运行APP, //还是BKP_COPY模式,如果拷贝模式校验值不对,进入BKP_IAP模式 uint8_t *pRunApp = (uint8_t *)APP_ADDR; uint8_t *pNewApp = (uint8_t *)STARTADDR; uint16_t crcValue = crc16_ccitt(pRunApp,RUNAPPVer.length); if(crcValue==RUNAPPVer.CRCValue) { Jump_App(); } //校验不对,拷贝新版本固件 } case BKP_COPY_APP: //校验 { uint8_t *pRunApp = (uint8_t *)APP_ADDR; uint8_t *pNewApp = (uint8_t *)STARTADDR; uint16_t crcValue = crc16_ccitt(pNewApp,NEWAPPVer.length); if(crcValue==NEWAPPVer.CRCValue) { APP_VER Appver; memcpy(&Appver,&NEWAPPVer,sizeof(NEWAPPVer)); EEWriteStruct(pNewApp,NEWAPPVer.length,APP_ADDR); //复制Flash EEWriteStruct(&Appver,sizeof(NEWAPPVer),NewAPPInfoAddr); //更新新的APP校验信息 WriteBKP(BKP_RUN); // while(1);//等待重启后直接运行 }//新版本APP校验不对,进入升级模式 } case BKP_IAP: InitGPRSConnect(); break; case BKP_RUN: default: Jump_App(); break; } } uint16_t crccheckOK(unsigned char *buf,int Count) { int i = 0; uint16_t crc16 =0; uint16_t crc16_2 = crc16_ccitt(buf+PACKHEADLEN,Count-PACKHEADLEN-2); for(i=2;i>0;i--) { crc16<<=8; crc16 |= buf[receCount-i]; } return (crc16_2==crc16); } //带返回值的宏 //超时为1 返回为0 #define GetRecvTimeOut()\ {\ PT_WAIT_THREAD(pt1,Recv_thread(&Pt_rcv)); \ beenReceived>0?0:1;\ } int ymodem_init(modem_struct *mblock) { int stat; int max_tries = MODEM_MAX_RETRIES; int crc_tries =MODEM_CRC_RETRIES; mblock->rec_err = 0; return -1; } int copyData(modem_struct *mblock,uint8_t *Buf,int len) { bCRCOK=crccheckOK(Buf,len); if(!bCRCOK) //校验出错 返回退出 return false; mblock->cur_num = ~Buf[2]; if((Buf[1]==mblock->cur_num)&&(Buf[1]==mblock->nxt_num)) { mblock->nxt_num++; memcpy(mblock->cachePtr,Buf+PACKHEADLEN,mblock->DataLenPerPack); mblock->cachePtr+=mblock->DataLenPerPack; //接受缓冲区首地址初始化 mblock->willbeSavePackCnt+=mblock->DataLenPerPack; if(mblock->willbeSavePackCnt==SECTOR_SIZE) { //保存数据 EEWriteStruct(mblock->buf,SECTOR_SIZE,mblock->FlashAddr); //然后保存接收指针清0 mblock->cachePtr = mblock->buf; mblock->willbeSavePackCnt = 0; mblock->FlashAddr+= SECTOR_SIZE; //接收数据的首地址; } Send2(MODEM_ACK); return true; } else { Send2(MODEM_NAK); return false; } } int GetCharCnt(uint8_t chr,uint8_t *Buf,int len) { int result = 0; int i =0; for( i=0;icur_num = Buf[1]; switch (Buf[0]) { case MODEM_SOH : mblock->DataLenPerPack = 128; copyData(mblock,Buf,len); if(mblock->EOT) { return InitYModemHeader(&Ymodem,receBuf,receCount); } else { copyData(mblock,Buf,len); } break; case MODEM_STX : mblock->DataLenPerPack = 1024; copyData(mblock,Buf,len); break; case MODEM_CAN : if(Buf[0]==MODEM_CAN) { //强制断开....退出吧 return -1; } break; case MODEM_EOT : //第一次收到回NAK 第二次回ACK和C EOTCnt++; if(EOTCnt==1) { Send2(MODEM_NAK); } else { Send2(MODEM_ACK); //保存数据 EEWriteStruct(mblock->buf,mblock->willbeSavePackCnt,mblock->FlashAddr); mblock->EOT = 1; Send2('C'); //数据搬运准备重启 /* if (mblock->modemtype == Y_MODEM) //Ymodem协议为批文件传输协议 { Send2(MODEM_C); //单个文件需 C ACK C后会自动停止传输 Send2(MODEM_ACK); Send2(MODEM_C); modem_cancle(); //多个文件强制停止传输 } */ } break; default: return -2; } return len; } //enum BKP_CMD{BKP_RUN,BKP_IAP,BKP_COPY_APP}; int InitYModemHeader(modem_struct *mblock,uint8_t* buff,int32_t len) { int decodeOK = false; bCRCOK=crccheckOK(buff,len); if((bCRCOK)&&(buff[1]==0)) { int fileNameLen = strlen((const char *)&buff[3]); if(fileNameLen==0) { APP_VER ver; uint8_t *pNewApp = (uint8_t *)STARTADDR; memcpy(ver.HW_VER,RUNAPPVer.HW_VER,sizeof(RUNAPPVer.HW_VER)); memcpy(ver.SW_VER,RUNAPPVer.SW_VER,sizeof(RUNAPPVer.SW_VER)); ver.length = mblock->FileLength; ver.CRCValue = crc16_ccitt(pNewApp,mblock->FileLength); EEWriteStruct(&ver,mblock->FileLength,NewAPPInfoAddr);//写入FLASH大小校验信息 //检查校验值,将校验值写入校验结束寄存器 WriteBKP(BKP_COPY_APP); //拷贝模式 //////////////////////////////////// Send2(MODEM_ACK); while(1); //等待重启 decodeOK = false; } else { strcpy(Ymodem.filename,(const char *)&buff[3]); mblock->FileLength = atoi((const char *)&buff[3+fileNameLen]); mblock->FlashAddr = STARTADDR; //烧录数据的首地址 mblock->cachePtr = Ymodem.buf; //接受缓冲区首地址初始化 mblock->willbeSavePackCnt = 0; mblock->nxt_num = 1; mblock->EOT = 0; Delay(20000); Send2(MODEM_ACK); Delay(20000); Send2('C'); decodeOK = true; } } return decodeOK; } void ErrForReBoot(void) { Ymodem.rec_err++; if(Ymodem.rec_err>MODEM_MAX_RETRIES) //错误次数太多,退出重启 { modem_cancle(); //多个文件强制停止传输 while(1); //重启 } } struct timer tZmodem; PT_THREAD(Thread_ZMODEM(struct pt *pt1)) { int RecResult = 0; static struct timer t; PT_BEGIN(pt1); //启动传输 while(beenReceived==0) { Send2('C'); PT_WAIT_THREAD(pt1,Recv_thread(&Pt_rcv)); //等待该线程返回 if(beenReceived>0) { if(InitYModemHeader(&Ymodem,receBuf,receCount)) { break; } } ErrForReBoot( ); timer_set(&tZmodem, 900); PT_WAIT_UNTIL(pt1, timer_expired(&tZmodem)); } while(1) { PT_WAIT_THREAD(pt1,(RecResult=Recv_thread(&Pt_rcv))); //等待该线程返回 if(Decode(receBuf,receCount,&Ymodem)>0) { // } else { ErrForReBoot(); } } PT_END(pt1); } static struct timer tRec1 = {0,0}; static PT_THREAD(Recv_thread(struct pt *pt1)) { __NOP(); PT_BEGIN(pt1); while(1) { timer_set(&tRec1, TT35); PT_WAIT_UNTIL(pt1,timer_expired(&tRec1)); timer_set(&tRec1, TT35); PT_WAIT_UNTIL(pt1,timer_expired(&tRec1)||(receTimeOut--==0)||(receCount==MAX_PACK_LEN)); beenReceived = receCount>0; //检查接收完成 PT_EXIT(pt1); } PT_END(pt1); } typedef void (*pFunction)(void); pFunction App_Run; void Jump_App(void) { uint32_t i,j; uint32_t AppAddress = *(__IO uint32_t*) (APP_ADDR + 4); //跳转到用户程序 App_Run = (pFunction) AppAddress; //初始化用户程序的堆栈指针 __set_MSP(*(__IO uint32_t*) APP_ADDR); App_Run(); } uint16_t ReadBKP(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问 return BKP_ReadBackupRegister(BKP_DR1); } void WriteBKP(uint16_t bkp) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问 BKP_WriteBackupRegister(BKP_DR1, bkp); }