From be89ccec2c2b9293daf051ee845c16e14a0447cd Mon Sep 17 00:00:00 2001 From: pvvx Date: Sat, 20 Jan 2024 08:01:10 +0300 Subject: [PATCH] fix, tested OTA --- .../SDK/components/driver/flash/flash.c | 3 +- .../{ota_phy62x2.ld => boot_ota_phy62x2.ld} | 0 .../{ota_phy6222.ld => ota_app_phy62x2.ld} | 128 ++++---- bthome_phy6222/source/ble_ota.c | 163 +++++----- bthome_phy6222/source/ble_ota.h | 34 +-- bthome_phy6222/source/bthome_beacon.h | 2 - bthome_phy6222/source/config.h | 6 +- bthome_phy6222/source/main.c | 6 +- bthome_phy6222/web/PHY62x2BTHome.html | 281 ++++++++++++------ 9 files changed, 383 insertions(+), 240 deletions(-) rename bthome_phy6222/SDK/misc/{ota_phy62x2.ld => boot_ota_phy62x2.ld} (100%) rename bthome_phy6222/SDK/misc/{ota_phy6222.ld => ota_app_phy62x2.ld} (60%) diff --git a/bthome_phy6222/SDK/components/driver/flash/flash.c b/bthome_phy6222/SDK/components/driver/flash/flash.c index 22252f1..bb37838 100644 --- a/bthome_phy6222/SDK/components/driver/flash/flash.c +++ b/bthome_phy6222/SDK/components/driver/flash/flash.c @@ -67,7 +67,8 @@ __ATTR_SECTION_SRAM__ static inline void spif_unlock(uint32_t vic_iser) { HAL_EXIT_CRITICAL_SECTION(); } -static void hal_cache_tag_flush(void) { +//static +void hal_cache_tag_flush(void) { HAL_ENTER_CRITICAL_SECTION(); uint32_t cb = AP_PCR->CACHE_BYPASS; volatile int dly = 8; diff --git a/bthome_phy6222/SDK/misc/ota_phy62x2.ld b/bthome_phy6222/SDK/misc/boot_ota_phy62x2.ld similarity index 100% rename from bthome_phy6222/SDK/misc/ota_phy62x2.ld rename to bthome_phy6222/SDK/misc/boot_ota_phy62x2.ld diff --git a/bthome_phy6222/SDK/misc/ota_phy6222.ld b/bthome_phy6222/SDK/misc/ota_app_phy62x2.ld similarity index 60% rename from bthome_phy6222/SDK/misc/ota_phy6222.ld rename to bthome_phy6222/SDK/misc/ota_app_phy62x2.ld index 66cebe6..2b92090 100644 --- a/bthome_phy6222/SDK/misc/ota_phy6222.ld +++ b/bthome_phy6222/SDK/misc/ota_app_phy62x2.ld @@ -1,11 +1,23 @@ - +/* SRAM + XIP linker script */ +/* https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/6n33n7fds/index.html */ +PHDRS +{ + romdata PT_LOAD FLAGS(6); + text PT_LOAD FLAGS(5); + data PT_LOAD FLAGS(6); + xip PT_LOAD FLAGS(5); + rodata PT_LOAD FLAGS(4); +} MEMORY { - jumptbl (rwx) : ORIGIN = 0x1fff0000, LENGTH = 0x00400 + jumptbl (rw) : ORIGIN = 0x1fff0000, LENGTH = 0x00400 gcfgtbl (rw) : ORIGIN = 0x1fff0400, LENGTH = 0x00400 - flash (rx) : ORIGIN = 0x11005000, LENGTH = 0x0B000 - sram (rwx) : ORIGIN = 0x1fff1838, LENGTH = 0x0E7C8 + sram (rwx) : ORIGIN = 0x1fff1838, LENGTH = 0x0E7C8 + flash (rx) : ORIGIN = 0x11020000, LENGTH = 0x20000 + sram2 (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 + sram3 (rwx) : ORIGIN = 0x20010000, LENGTH = 0x02000 + sram4 (rwx) : ORIGIN = 0x20012000, LENGTH = 0x00800 } OUTPUT_ARCH(arm) @@ -15,44 +27,21 @@ ENTRY(__start) SECTIONS { .jumptbl : { - KEEP(*(jump_table_mem_area)) - } > jumptbl + *(jump_table_mem_area) + } > jumptbl : romdata - - .gcfgtbl : { - *(global_config_area) + .gcfgtbl (NOLOAD) : { + *(global_config_area) } > gcfgtbl .textentry : { *(*.isr_vector) - } > sram + } > sram : text - - .init_section : { - _sinit = ABSOLUTE(.); - *(.init_array .init_array.*) - _einit = ABSOLUTE(.); - } > flash - - .ARM.extab : { - *(.ARM.extab*) - } > flash - - __exidx_start = ABSOLUTE(.); - .ARM.exidx : { - *(.ARM.exidx*) - } > flash - __exidx_end = ABSOLUTE(.); - - - ._sjtblsstore : { - _sjtblss = ABSOLUTE(.); - } > flash - - - .data : { - _sdata = ABSOLUTE(.); + _sdata = ABSOLUTE(.); + .text : { _stextram = ABSOLUTE(.); + *phy6222_start.o(.text) *.o(_section_standby_code_) *.o(_section_sram_code_) @@ -69,22 +58,18 @@ SECTIONS *phy_sec_ext.o(.text .text.*) - *libc.a:lib_a-memset.o(.text.*) - *libc.a:lib_a-memcpy-stub.o(.text.*) - *libgcc.a:_udivsi3.o(.text) - *libgcc.a:_divsi3.o(.text) - *libgcc.a:_dvmd_tls.o(.text) -/* *libgcc.a:_thumb1_case_sqi.o(.text) - *libgcc.a:_thumb1_case_uqi.o(.text) */ + *libgcc.a:*.o(.text .text.*) _etextram = ABSOLUTE(.); + } > sram : text + .data : { *(.data .data.*) *(.gnu.linkonce.d.*) CONSTRUCTORS - . = ALIGN(4); - _edata = ABSOLUTE(.); - } > sram + } > sram : data + . = ALIGN(4); + _edata = ABSOLUTE(.); .bss : { _sbss = ABSOLUTE(.); @@ -94,21 +79,24 @@ SECTIONS . = ALIGN(4); _ebss = ABSOLUTE(.); } > sram - - /* - .int_stack : { - . = ALIGN(4); - *(int_stack) - . = ALIGN(4); - _stack_top = ABSOLUTE(.); - } > sram -*/ - /* stack 32 kbytes */ - g_top_irqstack = ORIGIN(sram) + LENGTH(sram); - .common_text : { + .irq_stack : { + *(g_irqstack_base) + } > sram + + g_stack = ORIGIN(sram) + LENGTH(sram); + + .xip : { _stext = ABSOLUTE(.); - *(.text .text.*) + + *.o(_func_xip_code_) + *.o(_section_xip_code_) + *(.text .text.*) + + _etext = ABSOLUTE(.); + } > flash : xip + + .rodata : { *(.rodata .rodata.*) *(.fixup) *(.gnu.warning) @@ -119,8 +107,27 @@ SECTIONS *(.got) *(.gcc_except_table) *(.gnu.linkonce.r.*) - _etext = ABSOLUTE(.); - } > flash + } > flash : rodata + + .init_section : { + _sinit = ABSOLUTE(.); + *(.init_array .init_array.*) + _einit = ABSOLUTE(.); + } > flash : rodata + + .ARM.extab : { + *(.ARM.extab*) + } > flash : rodata + + .ARM.exidx : { + __exidx_start = ABSOLUTE(.); + *(.ARM.exidx*) + __exidx_end = ABSOLUTE(.); + } > flash : rodata + + ._sjtblsstore : { + _sjtblss = ABSOLUTE(.); + } > flash : rodata /* Stabs debugging sections. */ .stab 0 : { *(.stab) } @@ -137,4 +144,3 @@ SECTIONS .debug_aranges 0 : { *(.debug_aranges) } } - diff --git a/bthome_phy6222/source/ble_ota.c b/bthome_phy6222/source/ble_ota.c index 3202e0e..4eef186 100644 --- a/bthome_phy6222/source/ble_ota.c +++ b/bthome_phy6222/source/ble_ota.c @@ -13,21 +13,24 @@ /******************************************************************************* * CONSTANTS */ -#define ota_timeout_us 30000; // default 30 second + /******************************************************************************* * Prototypes */ + +/* Заголовок OTA */ typedef struct _app_info_t { - uint32_t flag; - uint32_t seg_count; - uint32_t start_addr; - uint32_t app_size; + uint32_t flag; // id = START_UP_FLAG + uint32_t seg_count; // кол-во сегментов + uint32_t start_addr; // стартовый/run адрес + uint32_t app_size; // размер OTA без 4-х байт CRC32 } app_info_t; +/* Описание сегментов OTA */ typedef struct _app_info_seg_t { - uint32_t faddr; - uint32_t size; - uint32_t saddr; - uint32_t chk; + uint32_t faddr; // адрес записи в Flash + uint32_t size; // размер сегмента + uint32_t saddr; // рабочий адрес + uint32_t chk; // не используется } app_info_seg_t; /******************************************************************************* @@ -36,14 +39,10 @@ ota_par_t ota = { .err_flag = OTA_SUCCESS, .version = 1, .start_flag = 0, - .reboot_flag = 0, .program_offset = FADDR_APP_SEC, .pkt_index = -1, .fw_value = START_UP_FLAG, }; -/********************************************************************* -* EXTERNAL VARIABLES */ - /********************************************************************* * LOCAL FUNCTION */ @@ -91,12 +90,32 @@ uint32_t get_crc32_16bytes(unsigned int crc_init, unsigned char *data) { (unsigned int*) crc32_half_tbl, 32); } +/* Speed: ~180 kbytes/s */ +static uint32_t ota_test_crc(void) { + uint32_t crc = 0xffffffff; + unsigned char * faddr = (unsigned char *)(ota.program_offset + 4); + int len = ota.pkt_total-2; + uint8_t buf[16]; + osal_memcpy(&buf[0], &ota.fw_value, 4); + osal_memcpy(&buf[4], faddr, 12); + faddr += 12; + crc = get_crc32_16bytes(crc, buf); + while(len > 0) { + len--; + crc = get_crc32_16bytes(crc, faddr); + faddr += 16; + } + return crc; +} +/********************************************************************* +* GLOBAL FUNCTION */ + +/* Speed: ~157 bytes/s */ int ota_parser(unsigned char *pout, unsigned char *pmsg, unsigned int msg_size) { uint32_t tmp; uint16_t crc; uint16_t ota_adr = pmsg[0] | (pmsg[1] << 8); - uint8_t flash_check[16]; int err_flg = OTA_SUCCESS; if(msg_size >= 2) { if (ota_adr >= CMD_OTA_START) { @@ -108,60 +127,79 @@ int ota_parser(unsigned char *pout, unsigned char *pmsg, unsigned int msg_size) | (pmsg[5] << 24)); } else ota.erase_addr = FADDR_APP_SEC-1; - ota.fw_value = START_UP_FLAG; - ota.start_flag = 0; ota.err_flag = OTA_SUCCESS; + ota.start_flag = 0; + ota.debug_flag = 0; + ota.program_offset = FADDR_APP_SEC; + ota.pkt_index = -1; + ota.pkt_total = 0; + ota.fw_value = START_UP_FLAG; } else if (ota_adr == CMD_OTA_SET) { if(ota.start_flag) { err_flg = OTA_NO_START; - } else if(msg_size >= 2 + 10) { - ota.program_offset = ((pmsg[2] & 0xf0) - | (pmsg[3] << 8) - | (pmsg[4] << 16) - | (pmsg[5] << 24)); - ota.fw_value = (pmsg[6] - | (pmsg[7] << 8) - | (pmsg[8] << 16) - | (pmsg[9] << 24)); - ota.pkt_total = (pmsg[10] - | (pmsg[11] << 8)); - if(ota.program_offset >= FADDR_APP_SEC - && ota.program_offset + (ota.pkt_total << 4) <= FLASH_MAX_SIZE) { - ota.pkt_index = -1; + } else { + if(msg_size == 2 + 10) { + ota.program_offset = ((pmsg[2] & 0xf0) + | (pmsg[3] << 8) + | (pmsg[4] << 16) + | (pmsg[5] << 24)); + ota.fw_value = (pmsg[6] + | (pmsg[7] << 8) + | (pmsg[8] << 16) + | (pmsg[9] << 24)); + ota.pkt_total = (pmsg[10] + | (pmsg[11] << 8)); + if(ota.program_offset >= FADDR_APP_SEC + && ota.program_offset + (ota.pkt_total << 4) + <= FADDR_START_ADDR + FLASH_MAX_SIZE) { + ota.start_flag = 1; //set flag + } else + err_flg = OTA_ERR_PARAM; // invalid offset + } else if(msg_size == 2) ota.start_flag = 1; //set flag - } else - err_flg = OTA_ERR_PARAM; // invalid offset - } else - err_flg = OTA_PKT_SIZE_ERR; // size error + else + err_flg = OTA_PKT_SIZE_ERR; // size error + } } else if (ota_adr == CMD_OTA_END) { //go to reboot or start app GAPRole_TerminateConnection(); + if(msg_size == 2 + 4) { + tmp = ((pmsg[2]) + | (pmsg[3] << 8) + | (pmsg[4] << 16) + | (pmsg[5] << 24)); + write_reg(OTA_MODE_SELECT_REG, tmp); + } hal_system_soft_reset(); } else - err_flg = OTA_UNKNOWN_CMD; // unknown commad + err_flg = OTA_UNKNOWN_CMD; // unknown command } else if(ota.err_flag) { // stop - old error } else if(ota.start_flag) { - if (ota.pkt_index + 1 == ota_adr) { // correct OTA data index - if(msg_size < 2+16+2) { + if (ota_adr == (uint16_t)(ota.pkt_index + 1)) { // correct OTA data index + if(msg_size >= 6) { crc = (pmsg[19] << 8) | pmsg[18]; if (crc == crc16(pmsg, 18)) { if (ota_adr == 0) { - ota.crc32 = 0xFFFFFFFF; // crc init set to 0xFFFFFFFF tmp = ((pmsg[2]) | (pmsg[3] << 8) | (pmsg[4] << 16) | (pmsg[5] << 24)); if (tmp != ota.fw_value) // id != ? err_flg = OTA_FW_CHECK_ERR; - } else if (ota_adr == ota.pkt_total - 1) { + else if(ota.pkt_total == 0) { + tmp = (pmsg[14] + | (pmsg[15] << 8) + | (pmsg[16] << 16)); + ota.pkt_total = (tmp >> 4) + 1; + } + } else if (ota_adr == (uint16_t)(ota.pkt_total - 1)) { tmp = ((pmsg[2]) | (pmsg[3] << 8) | (pmsg[4] << 16) | (pmsg[5] << 24)); - if (ota.crc32 != tmp) // crc32 != ? - err_flg = OTA_FW_CRC32_ERR; - else { + ota.crc32 = ota_test_crc(); + if(ota.crc32 == tmp) { hal_flash_write(ota.program_offset, (uint8_t*) &ota.fw_value, 4); hal_flash_read(ota.program_offset, @@ -170,16 +208,16 @@ int ota_parser(unsigned char *pout, unsigned char *pmsg, unsigned int msg_size) err_flg = OTA_END; } else err_flg = OTA_WRITE_FLASH_ERR; // flash write err - } + } else + err_flg = OTA_FW_CRC32_ERR; } - if (((ota_adr == 0) || ota_adr < ota.pkt_total - 1)) - ota.crc32 = get_crc32_16bytes(ota.crc32, pmsg + 2); if (ota_adr < ota.pkt_total) { tmp = (ota.program_offset + (ota_adr << 4)) & (~(FLASH_SECTOR_SIZE-1)); if (tmp > ota.erase_addr) { ota.erase_addr = tmp; hal_flash_erase_sector(tmp); + ota.debug_flag++; } if (ota_adr == 0) { pmsg[2] = 0xff; @@ -187,55 +225,42 @@ int ota_parser(unsigned char *pout, unsigned char *pmsg, unsigned int msg_size) pmsg[4] = 0xff; pmsg[5] = 0xff; } - hal_flash_write(ota.program_offset + (ota_adr << 4), - pmsg + 2, 16); - hal_flash_read(ota.program_offset + (ota_adr << 4), - flash_check, 16); - if (!osal_memcmp(flash_check, pmsg + 2, 16)) { // OK - ota.pkt_index = ota_adr; - } else - err_flg = OTA_WRITE_FLASH_ERR; // flash write err + hal_flash_write(ota.program_offset + (ota_adr << 4), pmsg + 2, 16); + ota.pkt_index = ota_adr; } else err_flg = OTA_OVERFLOW; } else - err_flg = OTA_PKT_CRC_ERR; // crc err + err_flg = OTA_PKT_CRC_ERR; // crc error } else err_flg = OTA_PKT_SIZE_ERR; // size error } else if (ota_adr <= ota.pkt_index) { // maybe repeated OTA data, we neglect it, do not consider it ERR } else - err_flg = OTA_PACKET_LOSS; // adr index err, missing at least one OTA data + err_flg = OTA_PACKET_LOSS; // addr index err, missing at least one OTA data } else err_flg = OTA_NO_PARAM; } else err_flg = OTA_PKT_SIZE_ERR; // size error if (err_flg != OTA_SUCCESS) { ota.err_flag = err_flg; - //send/Notify? + // send/Notify? osal_memcpy(pout, &ota, 20); return 20; } return 0; } +/********************************************************************* +* STARTUP FUNCTION */ __ATTR_SECTION_XIP__ static uint32_t start_app(void) { + app_info_t info_app; app_info_seg_t info_seg; uint32_t info_seg_faddr = FADDR_APP_SEC; spif_read(info_seg_faddr, (uint8_t*)&info_app, sizeof(info_app)); if(info_app.flag == START_UP_FLAG) { -/* Move OTA not released! - if(info_app.app_size != 0xFFFFFFFF) { - info_app.app_size += FLASH_SECTOR_SIZE-1; - info_app.app_size &= ~(FLASH_SECTOR_SIZE-1); - info_app.app_size += FADDR_START_ADDR; - spif_read(info_app.app_size, (uint8_t*)&info_app.flag, sizeof(info_app.flag)); - if(info_app.flag == START_UP_FLAG) - move_ota_app(info_app.app_size); - } -*/ if(info_app.seg_count <= 16) { while(info_app.seg_count) { info_seg_faddr += sizeof(info_app); @@ -260,6 +285,7 @@ static uint32_t start_app(void) { } #if defined ( __CC_ARM ) +#define __APP_RUN_ADDR__ (0x1FFF1838) __asm void __attribute__((section("ota_app_loader_area"))) jump2app(uint32_t entry) { LDR R0, = __APP_RUN_ADDR__ @@ -269,7 +295,7 @@ __asm void __attribute__((section("ota_app_loader_area"))) jump2app(uint32_t ent } #elif defined ( __GNUC__ ) __ATTR_SECTION_XIP__ -void jump2app(uint32_t entry) +static void jump2app(uint32_t entry) { __ASM volatile("ldr r0, %0\n\t" "ldr r1, [r0, #4]\n\t" @@ -280,14 +306,13 @@ void jump2app(uint32_t entry) #endif __ATTR_SECTION_XIP__ -void startup_ota(void) { +void startup_app(void) { uint32_t start_addr; HAL_ENTER_CRITICAL_SECTION(); start_addr = start_app(); if(start_addr) { - //AP_PCR->CACHE_BYPASS = 1; // bypass cache jump2app(start_addr); } } diff --git a/bthome_phy6222/source/ble_ota.h b/bthome_phy6222/source/ble_ota.h index 08e3392..6d9b208 100644 --- a/bthome_phy6222/source/ble_ota.h +++ b/bthome_phy6222/source/ble_ota.h @@ -18,8 +18,8 @@ #endif #define FADDR_START_ADDR 0x11000000 #define FADDR_BOOT_ROM_INFO (FADDR_START_ADDR + 0x02000) // 4k -#define FADDR_OTA_SEC (FADDR_START_ADDR + 0x03000) // 60k -#define FADDR_APP_SEC (FADDR_START_ADDR + 0x12000) // +#define FADDR_OTA_SEC (FADDR_START_ADDR + 0x03000) // 52k +#define FADDR_APP_SEC (FADDR_START_ADDR + 0x10000) // 176k+ //#define FADDR_DATA_SEC (FADDR_START_ADDR + 0x40000) #define FADDR_EEP_SEC (FADDR_START_ADDR + (FLASH_SIZE - 4*FLASH_SECTOR_SIZE)) @@ -30,20 +30,18 @@ #define CMD_OTA_END 0xff02 enum { - OTA_SUCCESS = 0, // success - OTA_UNKNOWN_CMD, // bad command - OTA_NO_START, // no start - OTA_NO_PARAM, // no parameters specified - OTA_ERR_PARAM, // invalid parameter(s) - OTA_PKT_SIZE_ERR, // packet size err - OTA_PKT_CRC_ERR, // packet CRC err - OTA_PACKET_LOSS, // lost one or more OTA PDU - OTA_WRITE_FLASH_ERR, // write OTA data to flash ERR - OTA_DATA_UNCOMPLETE, //lost last one or more OTA PDU - OTA_TIMEOUT, // timeout - OTA_OVERFLOW, // the ota adr overflow to 0x30000 - OTA_FW_CHECK_ERR, // - OTA_FW_CRC32_ERR, // + OTA_SUCCESS = 0, //0 success + OTA_UNKNOWN_CMD, //1 bad command + OTA_NO_START, //2 no start + OTA_NO_PARAM, //3 no parameters specified + OTA_ERR_PARAM, //4 invalid parameter(s) + OTA_PKT_SIZE_ERR, //5 packet size err + OTA_PKT_CRC_ERR, //6 packet CRC err + OTA_PACKET_LOSS, //7 lost one or more OTA PDU + OTA_WRITE_FLASH_ERR, //8 write OTA data to flash ERR + OTA_OVERFLOW, //9 the ota addr overflow + OTA_FW_CHECK_ERR, //10 + OTA_FW_CRC32_ERR, //11 OTA_END = 0xff }; @@ -51,7 +49,7 @@ typedef struct _ota_par_t { uint8_t err_flag; uint8_t version; uint8_t start_flag; - uint8_t reboot_flag; + uint8_t debug_flag; // debug flag uint32_t program_offset; uint16_t pkt_index; uint16_t pkt_total; @@ -65,7 +63,7 @@ extern ota_par_t ota; int ota_parser(unsigned char *pout, unsigned char *pmsg, unsigned int msg_size); #if OTA_TYPE == OTA_TYPE_BOOT -void startup_ota(void); +void startup_app(void); #endif #endif // OTA_TYPE diff --git a/bthome_phy6222/source/bthome_beacon.h b/bthome_phy6222/source/bthome_beacon.h index 7dd45c0..2ee4e4e 100644 --- a/bthome_phy6222/source/bthome_beacon.h +++ b/bthome_phy6222/source/bthome_beacon.h @@ -142,8 +142,6 @@ typedef struct _adv_buf_t { adv_bthome_ns1_t data; } adv_buf_t; -//extern adv_buf_t adv_buf; - //void bls_set_advertise_prepare(void *p); //int app_advertise_prepare_handler(rf_packet_adv_t * p); void bthome_data_beacon(padv_bthome_ns1_t p); diff --git a/bthome_phy6222/source/config.h b/bthome_phy6222/source/config.h index f04e58c..30e0687 100644 --- a/bthome_phy6222/source/config.h +++ b/bthome_phy6222/source/config.h @@ -40,9 +40,9 @@ #define DEVICE DEVICE_BTH01 #endif -#define OTA_TYPE_NONE 0 -#define OTA_TYPE_BOOT 1 -#define OTA_TYPE_APP 2 +#define OTA_TYPE_NONE 0 // нет OTA +#define OTA_TYPE_BOOT 1 // вариант для прошивки boot + OTA +#define OTA_TYPE_APP 2 // переключение из APP на OTA + boot прошивку, пока не реализовано #ifndef OTA_TYPE #define OTA_TYPE OTA_TYPE_BOOT diff --git a/bthome_phy6222/source/main.c b/bthome_phy6222/source/main.c index 8bee942..b79509c 100644 --- a/bthome_phy6222/source/main.c +++ b/bthome_phy6222/source/main.c @@ -295,9 +295,9 @@ int main(void) { && hal_gpio_read(GPIO_KEY) ) { spif_config(SYS_CLK_DLL_64M, 1, XFRD_FCMD_READ_DUAL, 0, 0); AP_PCR->CACHE_BYPASS = 1; // just bypass cache - startup_ota(); - } - write_reg(OTA_MODE_SELECT_REG, 0); + startup_app(); + } else + write_reg(OTA_MODE_SELECT_REG, 0); #endif watchdog_config(WDG_2S); diff --git a/bthome_phy6222/web/PHY62x2BTHome.html b/bthome_phy6222/web/PHY62x2BTHome.html index c32b567..22e718e 100644 --- a/bthome_phy6222/web/PHY62x2BTHome.html +++ b/bthome_phy6222/web/PHY62x2BTHome.html @@ -8,9 +8,11 @@ const FLASH_SIZE = 0x80000; var bluetoothDevice, gattServer, otaCharacteristic, myCharacteristic; //Firmware values -var firmwareArray = "", +var firmwareArray = null, startTime = 0, flgRdFF = false, + fwmaxsize = 196608, + fwname = "", blockCount = 0; //Connection values var connectTrys = 0; @@ -23,9 +25,7 @@ function resetVariables() { Theservice = null; otaCharacteristic = null; myCharacteristic = null; - $('butReadFF').disabled = true; $('butReadAddr').disabled = true; - $('butSave').disabled = true; $('butStartDFU').disabled = true; $('butWriteData').disabled = true; $('butCmdData').disabled = true; @@ -89,24 +89,30 @@ function doConnect() { }).then(characteristic => { addClog("Найдена OTA характеристика"); otaCharacteristic = characteristic; + return otaCharacteristic.addEventListener('characteristicvaluechanged', event => OtaBlkParse(event.target.value)); + }).then(_ => { + return otaCharacteristic.readValue(); + }).then(value => { + if(value.byteLength >= 20) + addLog("OTA: "+dump8(value, value.byteLength)); return Theservice.getCharacteristic(0xfff4); }).then(characteristic => { addClog("Найдена CMD характеристика"); myCharacteristic = characteristic; - myCharacteristic.readValue().then(value => { - if(value.byteLength >= 10) - addLog("DevCfg: "+dump8(value, value.byteLength)); - //flash_buf = new Uint8Array(FLASH_SIZE); - myCharacteristic.addEventListener('characteristicvaluechanged', event => CustomBlkParse(event.target.value)); - myCharacteristic.startNotifications().then(_ => { - let s = "Устройство подключено."; - addAlog(s); - $('butCmdData').disabled = false; - $('butReadFF').disabled = false; - $('butReadAddr').disabled = false; - $('butWriteData').disabled = false; - $('butStartDFU').disabled = false; }) - }) + return myCharacteristic.readValue(); + }).then(value => { + if(value.byteLength >= 10) + addLog("DevCfg: "+dump8(value, value.byteLength)); + return myCharacteristic.addEventListener('characteristicvaluechanged', event => CustomBlkParse(event.target.value)); + }).then(_ => { + myCharacteristic.startNotifications().then(_ => { + let s = "Устройство подключено."; + addAlog(s); + $('butCmdData').disabled = false; + $('butReadAddr').disabled = false; + $('butWriteData').disabled = false; + if (firmwareArray != null) $('butStartDFU').disabled = false; + }) }).catch(handleError); } @@ -119,7 +125,7 @@ function reConnect() { } function startDFU() { - addLog("Start DFU"); + addLog("Старт программирования..."); updateBegin(); } @@ -149,7 +155,7 @@ function setStatus(status) { } function updateFail(err) { - let s = "Update error: " + err; + let s = "OTA error: " + err; addAlog(s); } @@ -241,35 +247,130 @@ function hex2ascii(hexx) { return str; } +var crc32 = (function() { + let table = new Uint32Array(256); + for(var i=256; i--;) { + let tmp = i; + for(let k=8; k--;) { + tmp = tmp & 1 ? 0xEDB88320 ^ tmp >>> 1 : tmp >>> 1; + } + table[i] = tmp; + } + return function( data ) { + let crc = -1; + let l = data.length; + for(let i=0; i>> 8 ^ table[ crc & 255 ^ data[i] ]; + } + return (crc >>> 0); + }; +})(); + +function testOTAFirmware(data) { + let fsize = data.byteLength; + addClog("File size = 0x"+ fsize.toString(16)); + if (fsize < 272) + return "Неправильный размер двоичной прошивки PHY6 OTA!"; + if(fsize > 192*1024) // 208kB for BLE + return "Размер прошивки более 192 кбайт!"; + let head = new DataView(data, 0, 272); + let h = {}; + h.id = head.getUint32(0, true); + h.segs = head.getUint32(4, true); + h.start = head.getUint32(8, true); + h.size = head.getUint32(12, true); + addAlog("PHY6 OTA ID: "+hex(h.id, 4)+ ", Сегментов: " + h.segs + ", Старт: 0x"+hex(h.start, 8)+ ", Размер: " + h.size + " байт"); + if(h.id != 0x36594850) // "PHY6" + return "Неверное id в заголовке PHY6 OTA!"; + if(h.segs > 16) + return "Неверное количество сегментов в заголовке PHY6 OTA!"; + if(h.size != fsize-4) + return "Неверный размер в заголовке PHY6 OTA!"; + let fcrc = new Uint32Array(2); + fcrc[0] = crc32(new Uint8Array(data.slice(0, h.size))); + let x = new DataView(data, h.size, 4); + fcrc[1] = x.getUint32(0, true); + addClog("Файл CRC = 0x" + fcrc[1].toString(16) + ", Расчет CRC = 0x" + fcrc[0].toString(16)); + if(fcrc[0] != fcrc[1]) { + return "Неправильный CRC в файле OTA!"; + } + return "ok"; +} + +function getFirmwareArray(data, filename) { + addAlog("Файл: " + filename); + addClog("Файл: " + filename); + let s = testOTAFirmware(data); + if(s != "ok") { + addAlog(s); + blockCount = 0; + firmwareArray = null; + fwname = ""; + //$("ldfrmw").innerHTML=s; + alert(s); + return; + } + firmwareArray = bytesToHex(data); + addAlog("Размер файла: " + (firmwareArray.length/2).toString(10) + " байт"); + if (firmwareArray.length % 32 !== 0) { // pad last block to 16bytes + var padHex = "ffffffffffffffffffffffffffffffff"; + firmwareArray += padHex.substr(0, 32 - firmwareArray.length % 32); + } + blockCount = firmwareArray.length / 32; + addAlog("Счетчик: " + blockCount + " блоков"); + fwname = filename; + $('butStartDFU').disabled = false; +} + window.onload = function() { document.querySelector("#file").addEventListener("change", function() { - var reader = new FileReader(); - reader.onload = function() { - firmwareArray = bytesToHex(this.result); - if(firmwareArray.substring(0,4)!="1234"){ - alert("Выбранный файл не для PHY62x2 OTA!"); - addLog("Выбранный файл не для PHY62x2 OTA!"); - blockCount = 0; - firmwareArray = ""; - return; - } - addLog("File was selected, size: " + firmwareArray.length / 2 + " bytes"); - + let reader = new FileReader(); + reader.fname = ""; + reader.onload = function() {getFirmwareArray(this.result, this.fname);}; + if (this.files[0] != null) + reader.readAsArrayBuffer(this.files[0]); + else + addLog("Файл не выбран"); }, false); +} - if (firmwareArray.length % 32 !== 0) { // pad last block to 16bytes - var padHex = "ffffffffffffffffffffffffffffffff"; - firmwareArray += padHex.substr(0, 32 - firmwareArray.length % 32); - } - blockCount = firmwareArray.length / 32; - addLog("Count: " + blockCount); - } - if (this.files[0] != null) - reader.readAsArrayBuffer(this.files[0]); - else - addLog("Файл не выбран"); - }, false); +var ota_errors = [ +'ok', +'Неверная команда', +'Не задан старт', +'Не заданы параметры', +'Неверные параметры', +'Неправильный размер пакета', +'Ошибка CRC16 пакета', +'Потеря пакетов', +'Ошибка записи в Flash', +'Ошибка в номере пакета', +'Ошибка идентификатора в файле программы', +'Ошибка CRC32 переданной программы']; - $("butSave").onclick = function() {download(flash_buf, 'ff.bin', 'application/octet-stream;charset=utf-8');}; +function get_msg_ota_err(err) { + if(err == 0) + return "ok"; + if(err == 255) + return "OTA end"; + if(err <= 11) + return ota_errors[err]; + return "Неизвестная ошибка"; +} + +function OtaBlkParse(value) { + if(value.byteLength < 20) return; + var ota = {}; + ota.err_flag = value.getUint8(0); + ota.version = value.getUint8(1); + ota.start_flag = value.getUint8(2); + ota.debug_flag = value.getUint8(3); + ota.program_offset = value.getUint32(4,true); + ota.pkt_index = value.getUint16(8,true); + ota.pkt_total = value.getUint16(10,true); + ota.fw_value = value.getUint32(12,true); + ota.crc32 = value.getUint32(16,true); + //addClog('otablk: '+dump8(value, value.byteLength)); + addClog('OTA read: ver: '+hex(ota.version,2)+', err: '+ota.err_flag+' - '+get_msg_ota_err(ota.err_flag)+', dbg: '+ota.debug_flag+', start: '+ota.start_flag+', offs: 0x'+hex(ota.program_offset,8)+', idx: 0x'+hex(ota.pkt_index,4)+', total: 0x'+hex(ota.pkt_total,4)+', crc: 0x'+hex(ota.crc32,8)); } function updateBegin() { @@ -277,21 +378,40 @@ function updateBegin() { addLog("Не выбран файл!"); return; } - setTimeout(function() { - otaCharSend("00ff").then(function(character) { - otaCharSend("01ff").then(function(character) { - setTimeout(function() { - startTime = new Date().getTime(); - sendOTAblock(0); - }, 300); - }).catch(function(err) { - updateFail(err); - }); - }).catch(function(err) { - updateFail(err); - }); - }, 500); + otaCharSend("00ff") + .then(_ => { otaCharacteristic.readValue().then(value => { +// otaCharSend("01ff"+firmwareArray.substring(16,24)+firmwareArray.substring(0,8)+hex((blockCount >> 8) | ((blockCount & 0xff) << 8),4)) + otaCharSend("01ff") + .then(_ => { otaCharacteristic.readValue().then(value => { + if(value.byteLength >= 2 && value.getUint8(0) == 0) { + setTimeout(function() { + startTime = new Date().getTime(); + sendOTAblock(0); + }, 100); + } else + addAlog("Ошибка N"+value.getUint8(0)+" OTA!"); + }).catch(function(err) {updateFail(err); }); + }).catch(function(err) {updateFail(err); }); + }).catch(function(err) {updateFail(err); }); + }).catch(function(err) {updateFail(err); }); + }, 100); +} + +function sendLastOTA() { + otaCharacteristic.readValue().then(value => { + if(value.byteLength >= 1 && value.getUint8(0) == 0xff) + addAlog("Программирование завершено за " + (new Date().getTime() - startTime) / 1000 + " секунды"); + else + addAlog("Ошибка ("+value.getUint8(0)+") OTA: " + get_msg_ota_err(value.getUint8(0))); + }).catch(function(err) { updateFail(err); }); +/* Сброс - отключен для теста + var data = "02ff"; + otaCharSend(data).then(_ => { + addAlog("Программирование завершено за " + (new Date().getTime() - startTime) / 1000 + " секунды"); + }).catch(function(err) { + updateFail(err); + }); */ } function sendOTAblock(blockNr) { @@ -299,22 +419,28 @@ function sendOTAblock(blockNr) { sendLastOTA(); return; } - setStatus("Передан блок N: " + blockNr + " из " + blockCount + ", " + Math.floor(blockNr / (blockCount * 1.0) * 100) + "% успеха, время от старта " + (new Date().getTime() - startTime) / 1000.0 + "сек"); + setStatus("Передан блок N: " + blockNr + " из " + blockCount + ", " + Math.floor(blockNr / (blockCount * 1.0) * 100) + "% успеха, время от старта " + (new Date().getTime() - startTime) / 1000.0 + " сек"); var blockNrString = getHexBLockCount(blockNr); var blockString = blockNrString + firmwareArray.substring(blockNr * 32, blockNr * 32 + 32); var blockCRC = getHexCRC(blockString); - otaCharSend(blockString + blockCRC).then(function(character) { + otaCharSend(blockString + blockCRC).then(_ => { + if (blockNr >= blockCount - 1) { + sendLastOTA(); + return; + } setTimeout(function() { if ((blockNr + 1) % 8 == 0) { - otaCharacteristic.readValue().then(function(result) { - addClog('Чтение OTA'); - sendOTAblock(blockNr + 1); - }).catch(function(err) { - updateFail(err); - }); - } else { - sendOTAblock(blockNr + 1); - } + otaCharacteristic.readValue().then(value => { + if(value.byteLength >= 1 && value.getUint8(0) == 0) + sendOTAblock(blockNr + 1); + else { + let s = get_msg_ota_err(value.getUint8(0)); + if(s != "ok") + addAlog("Ошибка ("+value.getUint8(0)+") на передаче блока "+blockNr+" OTA: "+s); + } + }).catch(function(err) { updateFail(err); }); + } else + sendOTAblock(blockNr + 1); }, 0); }).catch(function(err) { updateFail(err); @@ -327,22 +453,13 @@ function getHexBLockCount(count) { } -function sendLastOTA() { - var data = "02ff" + getHexBLockCount(blockCount - 1) + getHexBLockCount(~(blockCount - 1) & 0xffff); - otaCharSend(data).then(function(character) { - addAlog("Прошивка завершена за " + (new Date().getTime() - startTime) / 1000 + " секунд"); - }).catch(function(err) { - updateFail(err); - }); -} - var otaCharSend = function(data) { return new Promise(function(resolve, reject) { - //addClog("OTA: " + data); + //addClog("OTA send: " + data); otaCharacteristic.writeValue(hexToBytes(data)).then(function(character) { resolve("ok"); }).catch(function(err) { - reject("some error while sending char data"); + reject("Ошибка при отправке данных"); }); }); } @@ -353,7 +470,7 @@ var mainCharSend = function(data, characteristic) { characteristic.writeValue(hexToBytes(data)).then(function(character) { resolve("ok"); }).catch(function(err) { - reject("some error while sending char data"); + reject("Ошибка при отправке данных"); }); }); } @@ -472,8 +589,6 @@ function download(data, filename, type) {
Состояние: Ожидание соединения с устройством


- -

Чтение и запись памяти:
Адрес (hex):