RTL8710_SDK_GCC_VERSION/component/common/utilities/uart_ymodem.c
RtlduinoMan 1d3357d3b0 GCC SDK RTL8710 basic version (including the window platform cygwin installation and Ubuntu platform Linux Installation routines),
including cross compilation of the installation, compile, link, run, debug, and so on.
SDK implementation of the function:
1, WiFi connection settings (including AP mode and STA mode).
2, peripheral resource control (including GPIO, SPI, UART, IIC, etc.).
3, the user uses the sample method.
2016-09-08 20:52:17 +08:00

654 lines
16 KiB
C

/****************************************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; i<ptr->len; 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; i<ptr->len; 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; i<ymodem_ptr->len; 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;
}