/*============================================================================================ Copyright(c) 2018 Quectel Wierless Solution,Co.,Ltd. All Rights Reserved. Quectel Wireless Solution Proprietary and Confidential. ============================================================================*/ #include #include "quec_rtos.h" #include "gps_channel.h" #include "quec_gps_rom.h" #include "quec_hx_gps_update.h" #include "gps_debug.h" #include "quec_hx_apflash.h" #include "quec_hx_gps.h" #include "guilin_lite.h" #include "quec_gpio.h" #define XMODEM_SOH 0x01 #define XMODEM_STX 0x02 #define XMODEM_EOT 0x04 #define XMODEM_ACK 0x06 #define XMODEM_NAK 0x15 #define XMODEM_CAN 0x18 #define XMODEM_CRC_CHR 'C' #define XMODEM_CRC_SIZE 2 /* Crc_High Byte + Crc_Low Byte */ #define XMODEM_FRAME_ID_SIZE 2 /* Frame_Id + 255-Frame_Id */ #define XMODEM_DATA_SIZE_SOH 128 /* for Xmodem protocol */ #define XMODEM_DATA_SIZE_STX 1024 /* for 1K xmodem protocol */ #define USE_1K_XMODEM 1 /* 1 for use 1k_xmodem 0 for xmodem */ #define TIMEOUT_USEC 0 #define TIMEOUT_SEC 10 #define GNSS_UART_BAUD_230400 230400 #define GNSS_UART_BAUD_921600 921600 #define GNSS_UART_BAUD_115200 115200 #define GNSS_UART_BAUD_460800 460800 #define GNSS_UART_BAUD_1843200 1843200 void quec_gnss_power_on_off(int flags); #if (USE_1K_XMODEM) #define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_STX #define XMODEM_HEAD XMODEM_STX #else #define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_SOH #define XMODEM_HEAD XMODEM_SOH #endif void dump(void *buf, int len) { char *p = (char *)buf; int i; for(i = 0; i < len; i++) { if(i % 16 == 0) GPS_LOGI("%04x:", i); if(i % 16 == 8) GPS_LOGI(" -"); GPS_LOGI(" %02x", p[i]); if(i % 16 == 15) GPS_LOGI("\n"); } if(i % 16) GPS_LOGI("\n"); } unsigned short get_crc16 ( char *ptr, unsigned short count ) { unsigned short crc, i; crc = 0; while(count--) { crc = crc ^ (int) *ptr++ << 8; for(i = 0; i < 8; i++) { if(crc & 0x8000) crc = crc << 1 ^ 0x1021; else crc = crc << 1; } } return (crc & 0xFFFF); } /*阻塞式检测总线buffer是否存在数据*/ int select_read(int delay_time) { int buflen=0; unsigned int gps_flags = 0; QUEC_GPS_DEV_T * quec_gps = quec_get_gps_dev(); quec_rtos_flag_wait(quec_gps->gps_event_flag_ref,QUEC_GPS_DOWNLOAD_FIRM, QUEC_FLAG_OR_CLEAR, &gps_flags, delay_time); buflen=GPS_COM_GetByteStatus(); return buflen; } /*读取总线buffer中数据*/ int deal_read(char *ack_id,unsigned int len) { if(ack_id==NULL) { return -1; } int buflen=0; buflen=GPS_COM_GetByte_Buffer((char*)ack_id,len); if(buflen) { return buflen; } else { memset(ack_id,0,len); return 0; } } /*校验固件合法性*/ int check_firmware_is_vailed(firm_type t) { #if defined (HX_GNSS_CC11_SUPPORT) icoe_image_header_t header; #else uc_image_header_t header; #endif unsigned int buf[1024]; unsigned int fsize, checksum, i; unsigned short crc; size_t rByte; if(!quec_gnss_firm_open(t)){ return -1; } fsize = quec_gnss_get_firm_size(t); if(fsize == 0) return -1; while(fsize > sizeof(header)) { rByte = quec_gnss_read_firm_buffer(t,(char *)&header,sizeof(header)); #if 0 dump((char *)&header, sizeof(header)); GPS_LOGI("%04x\n,%04x\n,%04x\n,%04x\n,%04x\n,%04x\n,%04x\n,%04x\n", header.ih_magic, header.ih_checksum, header.ih_time, header.ih_size, header.ih_reserved, header.pkg_flash_addr, header.pkg_run_addr, header.ih_hcrc); #endif crc = get_crc16 ( (char *) &header, sizeof(header)-4); GPS_LOGI("crc16 [%08x]\n", crc); if((header.ih_hcrc & 0xFFFF) != crc) { GPS_LOGE("%s[err]crc is err",__func__); quec_gnss_firm_close(t); return -1; } fsize -= sizeof(header); fsize -= header.ih_size; checksum = 0; while(header.ih_size > 0) { if(header.ih_size >= 1024 ) rByte = 1024; else rByte = header.ih_size; memset(buf, 0, sizeof(buf)); rByte = quec_gnss_read_firm_buffer(t,(char *)buf,rByte); for(i = 0; i < (rByte+3)/4; i++) checksum += buf[i]; header.ih_size -= rByte; } GPS_LOGI("checksum [%08x]\n\n",checksum); if( checksum != header.ih_checksum) { GPS_LOGE("%s[err]checksum is err",__func__); quec_gnss_firm_close(t); return -1; } } quec_gnss_firm_close(t); return 0; } unsigned int send_request_and_response_is_ok(void) { unsigned int ret = 0; char cmd[20]={0}; char ack_id[64]={0}; char cnt = 50; int i=5; int len = 0; sprintf(cmd,"M!TM!TM!T"); while(cnt--) { GPS_COM_PutByte_Buffer(cmd, 9); #if defined (HX_GNSS_CC11_SUPPORT) memset(ack_id,0,64); while (select_read(5) && i-- > 0) { len = deal_read(ack_id+len,64); if(strchr((char *)ack_id, 'Y') && strchr((char *)ack_id, 'C')) { ret=1; cnt=0; break; } } #else if(select_read(5)) { memset(ack_id,0,4); deal_read(ack_id,4); //for(i=0;i<64;i++){ // GPS_LOGI("check nmea_data = %x", ack_id[i]); //} if(ack_id[0]=='Y' && ack_id[1]=='C') { ret = 1; break; } if(ack_id[0]=='C' && ack_id[1]=='Y') { ret = 1; break; } } else { GPS_LOGE("retry..."); } #endif } return ret; } int xmodem_send(firm_type t) { char packet_data[XMODEM_DATA_SIZE]; char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1]; int complete,retry_num,pack_counter,read_number,i; unsigned short crc_value; char ack_id = 'C'; int retry=0; //char name[100]={}; pack_counter = 0; // 包计数器清零 complete = 0; retry_num = 0; /*如果不存在固件就报错,退出程序。*/ if((quec_gnss_firm_open(t))==0){ GPS_LOGE("\n can't open this file or not exist! \n"); return -1; } else{ GPS_LOGI("Ready to send the file\n"); } GPS_LOGI("Waiting for signal C/NAK!\n"); /*while(retry<50) { if(select_read()) { deal_read(&ack_id,1); GPS_LOGI("%c",ack_id); if(ack_id == 'C') break; retry++; } }*/ GPS_LOGI("The signal NAK: %02x ok!!!\n",ack_id);//打印接收到的NAK信息 while(!complete) { switch(ack_id) { case XMODEM_CRC_CHR: // 接收到字符'C'开始启动传输,并使用CRC校验 GPS_LOGI("begining to Send file ...\n"); case XMODEM_ACK: //0x06 retry_num = 0; pack_counter++; ack_id = 0; read_number = quec_gnss_read_firm_buffer(t,packet_data, XMODEM_DATA_SIZE); if(read_number > 0)/*read_number为返回的读取实际字节数*/ { if(read_number < XMODEM_DATA_SIZE_STX)/*最后一包数据*/ { GPS_LOGI("Start filling the last frame!\n"); for(; read_number < XMODEM_DATA_SIZE; read_number++) packet_data[read_number] = 0x1A; // 不足128字节用0x1A填充 } frame_data[0] = XMODEM_HEAD; // 帧开始字符 frame_data[1] = (char)pack_counter; // 信息包序号 frame_data[2] = (char)(255 - frame_data[1]); // 信息包序号的补码 for(i=0; i < XMODEM_DATA_SIZE; i++) // 128字节的数据段 frame_data[i+3] = packet_data[i];//把收到的字符和信息头一起打包 crc_value = get_crc16(packet_data, XMODEM_DATA_SIZE); // 16位crc校验 frame_data[XMODEM_DATA_SIZE+3] = (char)(crc_value >> 8);// 高八位数据 frame_data[XMODEM_DATA_SIZE+4] = (char)(crc_value); //低八位数据 /* 发送1024+5字节数据 */ GPS_COM_PutByte_Buffer((char*)frame_data, XMODEM_DATA_SIZE+3+2); GPS_LOGI("read_number=%d pack_counter = %d\n",read_number,pack_counter); //ADD: process if(select_read(1000)) { deal_read(&ack_id,1); } if(ack_id == XMODEM_ACK) { GPS_LOGI("ACK Ok!!Ready sending next pack!\n"); GPS_LOGI(" Ok!\n"); } else { GPS_LOGE("ACK Error!\n"); GPS_LOGE("0x%02X\n",ack_id); //GPS_LOGE("pack_counter = %d\n", pack_counter); } } else // 文件发送完成 { ack_id = XMODEM_EOT; GPS_LOGI("Complete ACK\n"); GPS_LOGI("send XMODEM_EOT\r\n"); GPS_COM_PutByte_Buffer(&ack_id, 1); if(select_read(1000)) { deal_read(&ack_id,1); GPS_LOGI("ack_id=%x",ack_id); if(ack_id == XMODEM_ACK) { complete = 1; } } if(complete == 1) { GPS_LOGI("Send file successful!!!\n"); quec_gnss_firm_close(t); } else { GPS_LOGE("Send file failed!!!\n"); quec_gnss_firm_close(t); return -1; } } break; case XMODEM_NAK: if( retry_num++ > 10) { GPS_LOGE("Retry too many times,Quit!\n"); complete = 1; } else //重试,发送 { GPS_COM_PutByte_Buffer((char*)frame_data, XMODEM_DATA_SIZE + 5); //write_number = write(fd, frame_data, XMODEM_DATA_SIZE + 5); GPS_LOGD("Retry for ACK,%d...", pack_counter); //while((read(fd, &ack_id, 1)) <= 0); if(select_read(1000)) { //read(fd,&ack_id,1); deal_read(&ack_id,1); } if( ack_id == XMODEM_ACK ) GPS_LOGI("OK\n"); else GPS_LOGE("Error!\n"); } break; default: GPS_LOGE("Fatal Error! %d\n", ack_id); complete = 1; return -1; } } quec_gnss_firm_close(t); return 0; } /*check=>reset=>bootloader=>apflash=>firmware*/ extern int quec_gnss_type_check(void); extern int quec_hx_bckp_get(void); int hx_gnss_upgrade(unsigned int reset_pin_num) { unsigned int reset_sucess = 0; int downloader_bootload = 0; int downloader_firmware = 0; int downloader_apflash = 0; int i; int retry = 0; char name[20]={0}; char rbuf[1024]; int bootloader_file_sta=0; int firmware_file_sta=0; int apflash_file_sta = 0; unsigned int rByte=0; int gnss_rom_type = quec_gnss_type_check(); int gnss_vbckp_select = quec_hx_bckp_get(); if((2==gnss_rom_type)&&(0 == gnss_vbckp_select)){ gnss_rom_type = 3;//20231011 add type 3:ROM2不接备电 } quec_gnss_apflash_struct_t *gnss_apflash = get_hx_apflash_req_status(); GPS_LOGI("L26 1st start, chenck bootloader&firmware checksum\r\n"); //1st,check bootloader and firmware bootloader_file_sta = check_firmware_is_vailed(GNSS_BOOT_TYPE); firmware_file_sta = check_firmware_is_vailed(GNSS_KERNEL_TYPE); if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { if(gnss_apflash->en){ apflash_file_sta = check_firmware_is_vailed(GNSS_APFLASH_TYPE); } } if(bootloader_file_sta<0 || firmware_file_sta<0) { GPS_LOGE("L26 check error! bootloader_file_sta:%d,firmware_file_sta%d\r\n",bootloader_file_sta,firmware_file_sta); return HX_L26_INIT_CHECKSUM_ERROR; } GPS_LOGI("L26 2nd start,reset L26\r\n"); GPS_COM_Init(); #if defined (HX_GNSS_CC11_SUPPORT) GPS_COM_SetBaudRate(GNSS_UART_BAUD_1843200); #else GPS_COM_SetBaudRate(GNSS_UART_BAUD_230400); #endif quec_gnss_power_on_off(0); gps_delay_ms(50); quec_gnss_power_on_off(1); for(i = 0; i < 20; i++) { GPS_COM_PurgeFIFO(); reset_sucess = send_request_and_response_is_ok(); if(reset_sucess) { GPS_LOGI("L26 2rd ok\r\n"); break; } else { GPS_LOGE("L26 2rd err\r\n"); quec_gnss_power_on_off(0); gps_delay_ms(50); quec_gnss_power_on_off(1); } } if(!reset_sucess) { GPS_LOGE("L26 reset failed \r\n"); return HX_L26_INIT_RESET_ERROR; } GPS_LOGI("L26 3th start, downloader l26 bootloader\r\n"); //4th,send bootloader file to uc6226 GPS_COM_PurgeFIFO(); downloader_bootload = xmodem_send(GNSS_BOOT_TYPE); if(!downloader_bootload) { GPS_LOGI("L26 3th ok\r\n"); } else { GPS_LOGE("L26 downloader_bootload failed \r\n"); return HX_L26_INIT_DOWNLOAD_BOOT_ERROR; } #if defined (HX_GNSS_CC11_SUPPORT) quec_rtos_task_sleep_ms(100); #else //切换波特率1843200 GPS_COM_SetBaudRate(GNSS_UART_BAUD_1843200); while(retry<10) { if(select_read(500)) { rByte=deal_read((char*)rbuf,sizeof(rbuf)-1); rbuf[rByte] = 0; GPS_LOGI( "%s", rbuf); if(strstr(rbuf,"Begin to download from uart and run") != NULL)//此处根据厂商规定修改,实测发现厂商不同固件有区别 break; } else { GPS_LOGI("retry...\n"); retry++; } } #endif GPS_LOGI("L26 4th start,downloader l26 firmware \r\n"); if((1 == gnss_rom_type) ||(3 == gnss_rom_type)) { if(!apflash_file_sta && gnss_apflash->en){ GPS_LOGI("apflash check ok\r\n"); if(select_read(5)){/*clear buffer 发现有概率性升级失败可能rb数据没清*/ rByte=deal_read((char*)rbuf,sizeof(rbuf)-1); rbuf[rByte] = 0; GPS_LOGI( "%s", rbuf); } downloader_apflash = xmodem_send(GNSS_APFLASH_TYPE); if(!downloader_firmware) { GPS_LOGI("L26 4th ok\r\n"); } else { GPS_LOGE("L26 downloader_apflash failed \r\n"); return HX_L26_INIT_DOWNLOAD_APFLSH_ERROR; } #ifndef HX_GNSS_CC11_SUPPORT if(select_read(500)){ rByte=deal_read((char*)rbuf,sizeof(rbuf)-1); rbuf[rByte] = 0; GPS_LOGI( "%s", rbuf); } sprintf(name,"2\n"); GPS_COM_PutByte_Buffer((char*)name,2); if(select_read(500)){ rByte=deal_read((char*)rbuf,sizeof(rbuf)-1); rbuf[rByte] = 0; GPS_LOGI( "%s", rbuf); } #endif } else { GPS_LOGE("APFLASH\r\n"); } } if(select_read(5)){/*clear buffer 发现有概率性升级失败可能rb数据没清*/ rByte=deal_read((char*)rbuf,sizeof(rbuf)-1); rbuf[rByte] = 0; GPS_LOGI( "%s", rbuf); } downloader_firmware = xmodem_send(GNSS_KERNEL_TYPE); if(!downloader_firmware) { GPS_LOGI("L26 5th ok\r\n"); } else { GPS_LOGE("L26 downloader_kernel failed \r\n"); return HX_L26_INIT_DOWNLOAD_FIRMWARE_ERROR; } #if defined (HX_GNSS_CC11_SUPPORT) GPS_COM_SetBaudRate(GNSS_UART_BAUD_460800); #else GPS_COM_SetBaudRate(GNSS_UART_BAUD_230400); #endif retry = 0; while(retry<50) { if(select_read(1000) > 0) { rByte = deal_read((char*)rbuf,sizeof(rbuf)-1); rbuf[rByte] = 0; GPS_LOGI( "%s", rbuf); if(strstr(rbuf,"RMC") != NULL){ #ifndef HX_GNSS_CC11_SUPPORT GPS_COM_PutByte_Buffer("$CFGPRT,1,h0,230400,129,35\r\n",sizeof("$CFGPRT,1,h0,230400,129,35\r\n")); GPS_COM_PutByte_Buffer("$CFGSAVE\r\n",sizeof("$CFGSAVE\r\n")); #endif break; } } retry++; } GPS_COM_PurgeFIFO(); return HX_L26_INIT_NO_ERROR; } void quec_gnss_power_on_off(int flags) { if(gps_gpio_pin.pwr_en) { #if defined (__QUECTEL_PROJECT_EG915NLA_GK__) *(volatile unsigned long *)(GPIO_MFPR_ADDR(gps_gpio_pin.pwr_en)) = MFP_AF0; #else *(volatile unsigned long *)(GPIO_MFPR_ADDR(gps_gpio_pin.pwr_en)) = MFP_AF1; #endif /*power_enable脚配置为输出低,mos管导通,给gnss供电*/ GpioSetDirection(gps_gpio_pin.pwr_en, GPIO_OUT_PIN); GpioSetLevel(gps_gpio_pin.pwr_en, !flags); } else{ GuilinLite_Ldo_8_set(flags); if(flags) { GuilinLite_Ldo_8_set_1_8(); } } } int hx_gnss_open(void) { int ret = HX_L26_INIT_NO_ERROR; ret = hx_gnss_upgrade(gps_gpio_pin.rst); return ret; } int hx_gnss_close(void) { quec_gnss_power_on_off(0); return HX_L26_INIT_NO_ERROR; } static const unsigned short crc16tab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; unsigned short crc16_ccitt(const char *buf, int len) { register int counter; register unsigned short crc = 0; for (counter = 0; counter < len; counter++) crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ *(char *)buf++) & 0x00FF]; return crc; }