fix, tested OTA

This commit is contained in:
pvvx 2024-01-20 08:01:10 +03:00
parent c5e59be953
commit be89ccec2c
9 changed files with 383 additions and 240 deletions

View file

@ -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;

View file

@ -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) }
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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="Читать">