/****************************************uart _ymodem.c**************************************************/ #include "uart_ymodem.h" #include "osdep_service.h" #include "PinNames.h" /***************************************************************************************** * uart basic functions * ******************************************************************************************/ void uarty_irq(uint32_t id, SerialIrq event) { uart_ymodem_t *ptr = (uart_ymodem_t *)id; //u8 ch = 0; if(event == RxIrq) { if(ptr->uart_recv_index == 0){ RtlUpSemaFromISR(&ptr->uart_rx_sema);//up uart rx semaphore } if(ptr->uart_recv_index == RCV_BUF_SIZE) ptr->uart_recv_index = 0; //ch = serial_getc(&ptr->sobj); // printf("[%d] 0x%x\r\n", ptr->uart_recv_index, ch); ptr->uart_irq_buf[ptr->uart_recv_index++] = serial_getc(&ptr->sobj); ptr->tick_last_update = xTaskGetTickCountFromISR(); // update tick everytime recved data } if(event == TxIrq){ // uart_send_string(sobj, "\r\n8195a$"); // rcv_ch = 0; } } void uart_init(uart_ymodem_t *ptr) { // serial_t sobj; //uart init serial_init(&ptr->sobj,UART_TX,UART_RX); serial_baud(&ptr->sobj,UART_BAUDRATE); //set baudrate 38400 serial_format(&ptr->sobj, 8, ParityNone, 0); serial_irq_handler(&ptr->sobj, uarty_irq, (int)ptr); serial_irq_set(&ptr->sobj, RxIrq, 1); serial_irq_set(&ptr->sobj, TxIrq, 1); RtlInitSema(&ptr->uart_rx_sema, 0); } void uart_sendbyte(uart_ymodem_t *ptr,u8 sendc ) { serial_putc(&ptr->sobj, sendc); // printf(" uart send 0x%x\r\n",sendc); } int uart_recvbytetimeout(uart_ymodem_t *uart_ymodem,u8 *ptr) { int ret = 0; // static int uart_recv_buf_index = 0; // printf(" [%d] = %x\r\n",uart_ymodem->uart_recv_buf_index,uart_ymodem->uart_irq_buf[uart_ymodem->uart_recv_buf_index]); *ptr = uart_ymodem->uart_irq_buf[uart_ymodem->uart_recv_buf_index]; uart_ymodem->uart_recv_buf_index++; if(uart_ymodem->uart_recv_buf_index == RCV_BUF_SIZE) uart_ymodem->uart_recv_buf_index = 0; return ret; } void uart_rxempty(uart_ymodem_t *ptr) { /*clean uart recv buf*/ // printf("Uart_RxEmpty\r\n"); memset(ptr->uart_irq_buf, 0, RCV_BUF_SIZE); memset(ptr->uart_rcv_buf, 0, RCV_BUF_SIZE); ptr->uart_recv_buf_index = 0; ptr->uart_recv_index = 0; } /***************************************************************************************** * flash function * ******************************************************************************************/ int ymodem_flashwrite(int flashadd, u8 *pbuf, int len) { int ret = 0; flash_t flash; // if(!FLASH_ADDRESS_CHECK_WRITE_ERASE(flashadd)){ // ret = -1; // return ret; // } if( len == 0){ printf("input error,data length should not be null!\r\n"); ret = -1; return ret; } else //as 8711am only canbe r/w in words.so make len is 4-bytes aligmented. len += 4 - ((len%4)==0 ? 4 : (len%4)); while(len){ if(flash_write_word(&flash, flashadd, *(unsigned int *)pbuf) !=1 ){ printf("write flash error!\r\n"); ret = -1; return ret; } len -= 4; pbuf += 4; flashadd += 4; } return ret; } /****************************uart_ymodem_init**********************************/ void uart_ymodem_init(uart_ymodem_t *uart_ymodem_ptr) { // u32 ret = 0; #if CONFIG_CALC_FILE_SIZE u8 filename[33] = {0}; //file name: max 32 bytes+ '\0'=33 #endif //init uart struct uart_ymodem_ptr->cur_num = 0; uart_ymodem_ptr->filelen = 0 ; #if CONFIG_CALC_FILE_SIZE uart_ymodem_ptr->filename = &filename[0]; #endif uart_ymodem_ptr->len = 0; uart_ymodem_ptr->nxt_num = 0; uart_ymodem_ptr->modemtype = 2; //ymodem protocol uart_ymodem_ptr->rec_err = 0; uart_ymodem_ptr->crc_mode = 1; //crc check uart_ymodem_ptr->uart_recv_buf_index = 0; uart_ymodem_ptr->uart_recv_index = 0; uart_ymodem_ptr->image_address = IMAGE_TWO; // return uart_ymodem_ptr; } void uart_ymodem_deinit(uart_ymodem_t *ptr) { /* Free uart_rx-sema */ RtlFreeSema(&ptr->uart_rx_sema); /* Free serial */ serial_free(&ptr->sobj); /* Free uart_ymodem_t */ RtlMfree((u8 *)ptr,sizeof(uart_ymodem_t)); } #if CONFIG_CALC_FILE_SIZE unsigned int buf_filelen(u8 *ptr) { int datatype=10, result=0; if (ptr[0]=='0' && (ptr[1]=='x' && ptr[1]=='X')) { datatype = 16; ptr += 2; } for ( ; *ptr!='\0'; ptr++) { if (*ptr>= '0' && *ptr<='9') { result =result*datatype+*ptr-'0'; } else { if (datatype == 10) { return result; } else { if (*ptr>='A' && *ptr<='F') { result = result*16 + *ptr-55; //55 = 'A'-10 } else if (*ptr>='a' && *ptr<='f') { result = result*16 + *ptr-87; //87 = 'a'-10 } else { return result; } } } } return result; } #endif void modem_cancle(uart_ymodem_t *ptr) { uart_sendbyte(ptr,0x18); uart_sendbyte(ptr,0x18); uart_sendbyte(ptr,0x18); uart_sendbyte(ptr,0x18); uart_sendbyte(ptr,0x18); } int start_next_round(uart_ymodem_t *ptr) { int ret = 0; // printf(" uart ymodedm transfer %d block\r\n",ptr->nxt_num); //clean recv buf if(!ptr->rec_err){ uart_rxempty(ptr); } else{ ret = -1; printf("\r\n recv data error!"); } if (ptr->nxt_num == 0) { if (ptr->crc_mode) { uart_sendbyte(ptr,MODEM_C); //first receiver send c } else { uart_sendbyte(ptr,MODEM_NAK); } } else { if (ptr->rec_err) { uart_sendbyte(ptr,MODEM_NAK); } else { if (ptr->nxt_num == 1) { if (ptr->crc_mode) { uart_sendbyte(ptr,MODEM_ACK); uart_sendbyte(ptr,MODEM_C); } else { uart_sendbyte(ptr,MODEM_NAK); } } else { uart_sendbyte(ptr,MODEM_ACK); } } } return ret; } int data_write_to_flash(uart_ymodem_t *ptr) { int ret = 0; // uint32_t update_image_address = IMAGE_TWO; static int offset = 0x0; u32 data; static int flags = 1; //write update image header only once // int file_blk_size = 0 flash_read_word(&ptr->flash, OFFSET_DATA, &data); // file_blk_size = ((ptr->filelen - 1)/4096) + 1; if(data == ~0x0){ flash_write_word(&ptr->flash, OFFSET_DATA, ptr->image_address); } // printf("image_address get from flash = 0x%x\n\r",ptr->image_address); //erase flash where to be written,since ymodem blk size can be 128 or 1024,so, erase once when gather 4096 if(offset ==0 || (offset % 4096)==0){ flash_erase_sector(&ptr->flash, ptr->image_address + offset); } //write to flash //write back image size and address if(!flags){ flash_write_word(&ptr->flash, ptr->image_address, ptr->filelen); flash_write_word(&ptr->flash, ptr->image_address+4,0x10004000); flags = 1; } // ymodem_flashwrite(update_image_address + offset, ptr->uart_rcv_buf, ptr->len); device_mutex_lock(RT_DEV_LOCK_FLASH); flash_stream_write(&ptr->flash, ptr->image_address+offset, ptr->len, ptr->uart_rcv_buf); device_mutex_unlock(RT_DEV_LOCK_FLASH); offset += ptr->len; return ret; } int block_num_check(uart_ymodem_t *ptr) { u8 blk,cblk; int stat, ret = 0; /**************** check blk and blk complement *********************/ stat = uart_recvbytetimeout(ptr,&blk); //blk num,bytes 2 if (stat != 0) { ret = -1; } printf(" blk num = %x\r\n", blk); stat = uart_recvbytetimeout(ptr,&cblk); //block num complement,bytes 3 if (stat != 0) { ret = -1; } // printf(" block num cmpl = %x\r\n",cblk); if (blk+cblk != 0xff) { ret = -1; } return ret; } int calc_file_name_size(uart_ymodem_t *ptr,u8* bufptr) { int ret = 0; u8* nameptr = ptr->filename; while (*bufptr != '\0'){ *nameptr++ = *bufptr++; } *nameptr = '\0'; bufptr++; while (*bufptr == ' ') { bufptr++; } //file length ptr->filelen = buf_filelen(bufptr); return ret; } int crc_check(uart_ymodem_t *ptr) { u8 crch, crcl; u8 *in_ptr; int stat,i,ret = 0; u32 cksum = 0; stat = uart_recvbytetimeout(ptr,&crch); //CRC byte 1 if (stat != 0){ ret = 1; } // printf(" char recved CRC byte 1 = %x\r\n", crch); if (ptr->crc_mode){ stat = uart_recvbytetimeout(ptr,&crcl); //CRC byte 2 if (stat != 0){ ret = 1; } } // printf(" char recved CRC byte 2 = %x\r\n", crcl); #if CRC_CHECK for (i=0; ilen; i++) //sum check for last block { cksum += ptr->uart_rcv_buf[i]; } if(cksum == 0) { ret = 2; return ret; } if (ptr->crc_mode) { in_ptr = ptr->uart_rcv_buf; cksum = 0; for (stat=ptr->len ; stat>0; stat--) { cksum = cksum^(int)(*in_ptr++) << 8; for (i=8; i !=0; i--) { if (cksum & 0x8000) cksum = cksum << 1 ^ 0x1021; else cksum = cksum << 1; } } cksum &= 0xffff; if (cksum != (crch<<8 | crcl)) { ptr->rec_err = 1; ret = 1; } } else { for (i=0; ilen; i++) //sum check { cksum += ptr->uart_rcv_buf[i]; } if ((cksum&0xff)!=crch) { ptr->rec_err = 1; ret = 1; } } #endif return ret; } #if DUMP_DATA void flash_dump_data(uart_ymodem_t *ptr) { int i,offset = 0; u32 data; printf("flash dump data"); for(i = 0;i< ptr->filelen;i+=4){ flash_read_word(&ptr->flash, ptr->image_address + 0x10 + offset, &data); offset += 4; printf("%x ",data); } } #endif #if AUTO_REBOOT void auto_reboot(void) { // Set processor clock to default before system reset HAL_WRITE32(SYSTEM_CTRL_BASE, 0x14, 0x00000021); osDelay(100); // Cortex-M3 SCB->AIRCR HAL_WRITE32(0xE000ED00, 0x0C, (0x5FA << 16) | // VECTKEY (HAL_READ32(0xE000ED00, 0x0C) & (7 << 8)) | // PRIGROUP (1 << 2)); // SYSRESETREQ while(1) osDelay(1000); } #endif int set_signature(uart_ymodem_t *ptr) { int ret = 0; uint32_t sig_readback0,sig_readback1; uint32_t oldimg2addr; //old image address flash_read_word(&ptr->flash, 0x18, &oldimg2addr); oldimg2addr = (oldimg2addr&0xFFFF)*1024; printf(" lod image address 0x%x\n\r",oldimg2addr); //Set signature in New Image 2 addr + 8 and + 12 // flash_write_word(&ptr->flash,ptr->image_address + 8, 0x35393138);//0x35393138 // flash_write_word(&ptr->flash,ptr->image_address + 12, 0x31313738); // flash_read_word(&ptr->flash, ptr->image_address + 8, &sig_readback0); // flash_read_word(&ptr->flash, ptr->image_address + 12, &sig_readback1); // printf(" new signature %x,%x,\n\r",sig_readback0, sig_readback1); #if 1 flash_write_word(&ptr->flash,oldimg2addr + 8, 0x35393130); flash_write_word(&ptr->flash,oldimg2addr + 12, 0x31313738); flash_read_word(&ptr->flash, oldimg2addr + 8, &sig_readback0); flash_read_word(&ptr->flash, oldimg2addr + 12, &sig_readback1); printf(" old signature %x,%x\n\r",sig_readback0, sig_readback1); #endif printf(" set signature success!\n\r"); return ret; } static void uart_ymodem_thread(void* param) { u8 ch; u32 stat, error_bit = 0, transfer_over = 0; u32 can_counter = 0, eot_counter = 0; u32 i, send_count = 0 , ret = 0; static int first_time = 1; uart_ymodem_t *ymodem_ptr = (uart_ymodem_t *)param; printf(" ==>uart ymodem_task\r\n"); while(1) { //wait 2min,2*60*1000/100 if(send_count >= (2*60*10)){ error_bit = 6; printf("no response after 2min\r\n"); goto exit; } else{ if (ymodem_ptr->crc_mode){ uart_sendbyte(ymodem_ptr,MODEM_C); //first receiver send c } else{ uart_sendbyte(ymodem_ptr,MODEM_NAK); } send_count++; } if(xSemaphoreTake(ymodem_ptr->uart_rx_sema, 0) == pdTRUE){ RtlUpSema(&ymodem_ptr->uart_rx_sema); break; } else // send every 100ms vTaskDelay(100); } start: while(xSemaphoreTake(ymodem_ptr->uart_rx_sema, portMAX_DELAY) == pdTRUE){ // ymodem_ptr->tick_current = ymodem_ptr->tick_last_update = xTaskGetTickCount(); ymodem_ptr->tick_current = xTaskGetTickCount(); while((int)(ymodem_ptr->tick_current - ymodem_ptr->tick_last_update) < 50 ){ ymodem_ptr->tick_current = xTaskGetTickCount(); vTaskDelay(5); } printf("uart_recv_index = %d current=%d last=%d\r\n",ymodem_ptr->uart_recv_index, ymodem_ptr->tick_current, ymodem_ptr->tick_last_update); /*uart data recv done and process what we have recvied*/ stat = uart_recvbytetimeout(ymodem_ptr,&ch); if (stat == 0) { switch (ch) { case MODEM_SOH : ymodem_ptr->len = 128; // printf(" char recved was MODEM_SOH!\r\n"); break; case MODEM_STX : ymodem_ptr->len = 1024; // printf(" char recved was MODEM_STX!\r\n"); break; case MODEM_CAN : if ((++can_counter) >= MODEM_CAN_COUNT) { error_bit = 1; goto exit; } // printf(" char recved was MODEM_CAN!\r\n"); break; case MODEM_EOT : // printf(" char recved was MODEM_EOT!\r\n"); if ((++eot_counter) >= MODEM_EOT_COUNT) { uart_sendbyte(ymodem_ptr,MODEM_ACK); if (ymodem_ptr->modemtype == 2) //Ymodem protocol { uart_sendbyte(ymodem_ptr,MODEM_C); //first send a C uart_sendbyte(ymodem_ptr,MODEM_ACK); //then send ack uart_sendbyte(ymodem_ptr,MODEM_C); // and then send c modem_cancle(ymodem_ptr); //cancel the transits } transfer_over = 1; goto exit; } else { uart_sendbyte(ymodem_ptr,MODEM_ACK); uart_sendbyte(ymodem_ptr,MODEM_C); goto start; } break; default: error_bit = 1; goto exit; break; } } //block num check if(block_num_check(ymodem_ptr)){ error_bit = 2; goto exit; } #if CONFIG_CALC_FILE_SIZE // calculate file name and file size if(ymodem_ptr->nxt_num == 0 && first_time){ error_bit = calc_file_name_size(ymodem_ptr,&ymodem_ptr->uart_irq_buf[3]); // first_time = 0; } #endif //copy data from uart irq buf to uart recv buf without header for (i=0; ilen; i++) { stat = uart_recvbytetimeout(ymodem_ptr,&ymodem_ptr->uart_rcv_buf[i]); // printf(" data recv[%d] =%x\r\n",i,ymodem_ptr->uart_rcv_buf[i]); } //write data to flash,but do not write first block data if(ymodem_ptr->nxt_num != 0 || !first_time){ if(data_write_to_flash(ymodem_ptr)){ error_bit = 3; goto exit; } first_time = 0; } //crc check ret = crc_check(ymodem_ptr); if(ret == 1){ error_bit = 4; goto exit; } else if(ret == 2 && ymodem_ptr->nxt_num == 0xff){ printf(" next num = %x\r\n",ymodem_ptr->nxt_num); transfer_over = 1; goto exit; } #if 0 //avoid skip block uart_ymodem->cur_num = blk; if (blk != uart_ymodem->nxt_num) { error_bit = -1; } #endif ymodem_ptr->nxt_num++; ymodem_ptr->rec_err=0; //start another round if(start_next_round(ymodem_ptr)){ error_bit = 5; printf(" start next round failed!\r\n"); goto exit; } } exit: //if anything goes wrong or transfer over,we kill ourself. if(error_bit || transfer_over){ if(error_bit) printf("error!!! error bit = %d\r\n",error_bit); else{ printf(" [%s, %d Bytes] transfer_over!\r\n",ymodem_ptr->filename,ymodem_ptr->filelen); set_signature(ymodem_ptr); #if DUMP_DATA flash_dump_data(ymodem_ptr); #endif #if AUTO_REBOOT auto_reboot(); #endif } } first_time = 1; uart_ymodem_deinit(ymodem_ptr); vTaskDelete(NULL); } int uart_ymodem(void) { int ret = 0; uart_ymodem_t *uart_ymodem_ptr; printf("uart ymodem update start\r\n"); uart_ymodem_ptr = (uart_ymodem_t *)RtlMalloc(sizeof(uart_ymodem_t)); if(!uart_ymodem_ptr){ printf("uart ymodem malloc fail!\r\n"); ret = -1; return ret; } uart_ymodem_init(uart_ymodem_ptr); if(ret == -1){ ret = -1; return ret; } //uart initial uart_init(uart_ymodem_ptr); if(xTaskCreate(uart_ymodem_thread, ((const char*)"uart_ymodem_thread"), UART_YMODEM_TASK_DEPTH, uart_ymodem_ptr, UART_YMODEM_TASK_PRIORITY, NULL) != pdPASS) printf("%s xTaskCreate(uart_thread) failed\r\n", __FUNCTION__); return ret; }