THB2/bthome_phy6222/source/ble_ota.c
2024-01-31 16:37:06 +03:00

338 lines
9.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* @file ble_ota.c
*
******************************************************************************/
#include "bcomdef.h"
#include "config.h"
#if OTA_TYPE
#include "OSAL.h"
#include "flash.h"
#include "ble_ota.h"
#include "sbp_profile.h"
#include "thb2_peripheral.h"
/*******************************************************************************
* CONSTANTS */
/*******************************************************************************
* Prototypes */
/* Заголовок OTA */
typedef struct _app_info_t {
uint32_t flag; // id = START_UP_FLAG
uint32_t seg_count; // кол-во сегментов
uint32_t start_addr; // стартовый/run адрес (if = -1 -> берестя из первого значения != -1 у сегмента)
uint32_t app_size; // размер OTA без 4-х байт CRC32
} app_info_t;
/* Описание сегментов OTA */
typedef struct _app_info_seg_t {
uint32_t faddr; // адрес записи в Flash
uint32_t size; // размер сегмента
uint32_t waddr; // рабочий адрес
uint32_t chk; // не используется
} app_info_seg_t;
/*******************************************************************************
* LOCAL VARIABLES */
ota_par_t ota = {
.err_flag = OTA_SUCCESS,
.version = 1,
.start_flag = 0,
.program_offset = FADDR_APP_SEC,
.pkt_index = -1,
.fw_value = START_UP_FLAG,
};
/*********************************************************************
* LOCAL FUNCTION */
unsigned short crc16(unsigned char *pD, int len) {
static unsigned short poly[2] = { 0, 0xa001 }; //0x8005 <==> 0xa001
unsigned short crc = 0xffff;
int i, j;
for (j = len; j > 0; j--) {
unsigned char ds = *pD++;
for (i = 0; i < 8; i++) {
crc = (crc >> 1) ^ poly[(crc ^ ds) & 1];
ds = ds >> 1;
}
}
return crc;
}
static const unsigned int crc32_half_tbl[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
unsigned int crc32_half_cal(unsigned int crc, unsigned char *input,
unsigned int *table, int len) {
unsigned char *pch = input;
for (int i = 0; i < len; i++) {
crc = (crc >> 4) ^ table[(crc ^ *pch) & 0x0f];
pch++;
}
return crc;
}
uint32_t get_crc32_16bytes(unsigned int crc_init, unsigned char *data) {
// split 16 bytes OTA data into 32 half bytes to calculate CRC.
uint8_t ota_dat[32];
for (int i = 0; i < 16; i++) {
ota_dat[i * 2] = data[i] & 0x0f;
ota_dat[i * 2 + 1] = data[i] >> 4;
}
return crc32_half_cal(crc_init, ota_dat,
(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];
memcpy(&buf[0], &ota.fw_value, 4);
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: ~1 kbytes/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);
int err_flg = OTA_SUCCESS;
if(msg_size >= 2) {
if (ota_adr >= CMD_OTA_START) {
if (ota_adr == CMD_OTA_START) {
if(msg_size == 2 + 4) {
ota.erase_addr = (pmsg[2]
| (pmsg[3] << 8)
| (pmsg[4] << 16)
| (pmsg[5] << 24));
} else
ota.erase_addr = FADDR_START_ADDR;
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;
/* GAPRole_SendUpdateParam( gapRole_MinConnInterval, gapRole_MaxConnInterval,
0, gapRole_TimeoutMultiplier,
GAPROLE_RESEND_PARAM_UPDATE ); */
} 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)
<= 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_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 command
} else if(ota.err_flag) {
// stop - old error
} else if(ota.start_flag) {
if (ota_adr == (uint16_t)(ota.pkt_index + 1)) { // correct OTA data index
if(msg_size >= 20) {
crc = (pmsg[19] << 8) | pmsg[18];
if (crc == crc16(pmsg, 18)) {
if (ota_adr == 0) {
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 {
pmsg[2] = 0xff;
pmsg[3] = 0xff;
pmsg[4] = 0xff;
pmsg[5] = 0xff;
if(ota.pkt_total == 0) {
tmp = (pmsg[14]
| (pmsg[15] << 8)
| (pmsg[16] << 16));
ota.pkt_total = (tmp >> 4) + 1;
}
}
if(ota.pkt_total == 0)
err_flg = OTA_ERR_PARAM; // invalid offset
} else if (ota_adr == (uint16_t)(ota.pkt_total - 1)) {
tmp = ((pmsg[2])
| (pmsg[3] << 8)
| (pmsg[4] << 16)
| (pmsg[5] << 24));
ota.crc32 = ota_test_crc();
if(ota.crc32 == tmp) {
// write ID
hal_flash_write(ota.program_offset,
(uint8_t*) &ota.fw_value, 4);
hal_flash_read(ota.program_offset,
(uint8_t*) &tmp, 4);
if (ota.fw_value == tmp) // Write OK
err_flg = OTA_END;
else
err_flg = OTA_WRITE_FLASH_ERR; // flash write err
} else
err_flg = OTA_FW_CRC32_ERR;
}
if (err_flg == OTA_SUCCESS) {
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++;
}
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 error
} else
err_flg = OTA_PKT_SIZE_ERR; // size error
} else if (ota_adr < (uint16_t)(ota.pkt_index + 1)) {
// maybe repeated OTA data, we neglect it, do not consider it ERR
} else
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?
memcpy(pout, &ota, 20);
return 20;
}
return 0;
}
/*********************************************************************
* STARTUP FUNCTION */
__ATTR_SECTION_XIP__
static uint32_t start_app(void) {
uint32_t i;
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) {
if(info_app.seg_count <= 15) {
i = info_app.seg_count;
while(i--) {
if(info_app.start_addr == 0xffffffff) // если не назначен
// берется значение из первого сегмента отличного от -1
info_app.start_addr = info_seg.waddr;
}
if(info_app.start_addr != 0xffffffff) {
while(info_app.seg_count) {
info_seg_faddr += sizeof(info_app);
spif_read(info_seg_faddr, (uint8_t*)&info_seg, sizeof(info_seg));
if(info_app.start_addr == 0xffffffff) // если не назначен
// берется значение из первого сегмента отличного от -1
info_app.start_addr = info_seg.waddr;
info_seg.faddr += FADDR_START_ADDR;
info_seg.size &= 0x000fffff;
if (info_seg.waddr != info_seg.faddr // не XIP
//&& info_seg.waddr < 0x11000000
//&& info_seg.waddr > 0x11020000
&& info_seg.size < (128*1024)) { // < 128k
memcpy((void *)info_seg.waddr, (void *)info_seg.faddr, info_seg.size);
}
info_app.seg_count--;
}
} else
info_app.start_addr = 0;
}
} else
info_app.start_addr = 0;
return info_app.start_addr;
}
#if defined ( __CC_ARM )
//#define __APP_RUN_ADDR__ (0x1FFF1838)
__asm void __attribute__((section("ota_app_loader_area"))) jump2app(uint32_t entry)
{
LDR R0, = %0
LDR R1, [R0, #4]
BX R1
ALIGN
}
#elif defined ( __GNUC__ )
__ATTR_SECTION_XIP__
static void jump2app(uint32_t entry)
{
__ASM volatile("ldr r0, %0\n\t"
"ldr r1, [r0, #4]\n\t"
"bx r1"
:"+m"(entry)
);
}
#endif
__ATTR_SECTION_XIP__
void startup_app(void) {
uint32_t start_addr;
HAL_ENTER_CRITICAL_SECTION();
start_addr = start_app();
if(start_addr) {
jump2app(start_addr);
}
}
#endif // OTA_TYPE