fix, tested OTA
This commit is contained in:
parent
c5e59be953
commit
be89ccec2c
9 changed files with 383 additions and 240 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<l; i++) {
|
||||
crc = crc >>> 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) {
|
|||
<div id="percent">Состояние: Ожидание соединения с устройством</div>
|
||||
<button type="button"id="butStartDFU" disabled="true" onclick="startDFU();">Старт программирования</button>
|
||||
<br><hr>
|
||||
<input type="button" id="butReadFF" onclick="StartReadFF()" disabled="true" value="Прочитать всю Flash">
|
||||
<input type="button" id="butSave" disabled="true" value="Сохранить в файл"><br><hr>
|
||||
Чтение и запись памяти:<br>
|
||||
Адрес (hex): <input size="8" type="text" id="inputAddr" value="11000000" maxlength="8">
|
||||
<input type="button" id="butReadAddr" onclick="InfoReadAddr()" disabled="true" value="Читать">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue