Skip to content

Commit

Permalink
Merge pull request #1788 from particle-iot/feature/ch32507
Browse files Browse the repository at this point in the history
allow the bootloader to be flashed over DFU
  • Loading branch information
technobly committed Jun 14, 2019
2 parents 5165c25 + aa9484e commit 55fdc11
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 7 deletions.
1 change: 1 addition & 0 deletions hal/inc/hal_dynalib_ota.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ DYNALIB_FN(6, hal_ota, HAL_FLASH_Update, int(const uint8_t*, uint32_t, uint32_t,
DYNALIB_FN(7, hal_ota, HAL_FLASH_End, hal_update_complete_t(hal_module_t*))
DYNALIB_FN(8, hal_ota, HAL_FLASH_OTA_Validate, int(hal_module_t*, bool, module_validation_flags_t, void*))
DYNALIB_FN(9, hal_ota, HAL_OTA_Add_System_Info, void(hal_system_info_t* info, bool create, void* reserved))
DYNALIB_FN(10, hal_ota, HAL_FLASH_ApplyPendingUpdate, hal_update_complete_t(hal_module_t*, bool, void*))
DYNALIB_END(hal_ota)

#endif /* HAL_DYNALIB_OTA_H */
Expand Down
7 changes: 7 additions & 0 deletions hal/inc/ota_flash_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ typedef enum {

hal_update_complete_t HAL_FLASH_End(hal_module_t* module);

/**
* @param module Optional pointer to a module that receives the module definition of the firmware that was flashed.
* @param dryRun when true, only test that the system has a pending update in memory. When false, the test is performed and the module
* applied if valid (or the bootloader instructed to apply it.)
*/
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved);

uint32_t HAL_FLASH_ModuleAddress(uint32_t address);
uint32_t HAL_FLASH_ModuleLength(uint32_t address);
bool HAL_FLASH_VerifyCRC32(uint32_t address, uint32_t length);
Expand Down
2 changes: 1 addition & 1 deletion hal/src/core/ota_flash_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ int HAL_FLASH_OTA_Validate(hal_module_t* mod, bool userDepsOptional, module_vali
return 0;
}

hal_update_complete_t HAL_FLASH_End(hal_module_t* reserved)
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
FLASH_End();
return HAL_UPDATE_APPLIED_PENDING_RESTART;
Expand Down
6 changes: 5 additions & 1 deletion hal/src/gcc/ota_flash_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ int HAL_FLASH_OTA_Validate(hal_module_t* mod, bool userDepsOptional, module_vali
return HAL_UPDATE_APPLIED;
}


hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
HAL_FLASH_End(module);
return HAL_UPDATE_APPLIED_PENDING_RESTART;
}

/**
* Set the claim code for this device.
Expand Down
25 changes: 25 additions & 0 deletions hal/src/nRF52840/ota_flash_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,31 @@ hal_update_complete_t HAL_FLASH_End(hal_module_t* mod)
return result;
}

// Todo this code and much of the code here is duplicated between Gen2 and Gen3
// This should be factored out into directory shared by both platforms.
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
uint8_t otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
STATIC_ASSERT(sizeof(otaUpdateFlag)==DCT_OTA_UPDATE_FLAG_SIZE, "expected ota update flag size to be 1");
dct_read_app_data_copy(DCT_OTA_UPDATE_FLAG_OFFSET, &otaUpdateFlag, DCT_OTA_UPDATE_FLAG_SIZE);
hal_update_complete_t result = HAL_UPDATE_ERROR;
if (otaUpdateFlag==DCT_OTA_UPDATE_FLAG_SET) {
if (dryRun) {
// todo - we should probably check the module integrity too
// ideally this parameter would be passed to HAL_FLASH_End to avoid duplication of logic here.
result = HAL_UPDATE_APPLIED;
}
else {
// clear the flag
otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
dct_write_app_data(&otaUpdateFlag, DCT_OTA_UPDATE_FLAG_OFFSET, DCT_OTA_UPDATE_FLAG_SIZE);
result = HAL_FLASH_End(module);
}
}
return result;
}


void HAL_FLASH_Read_ServerAddress(ServerAddress* server_addr)
{
bool udp = HAL_Feature_Get(FEATURE_CLOUD_UDP);
Expand Down
25 changes: 25 additions & 0 deletions hal/src/stm32f2xx/ota_flash_hal_stm32f2xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,31 @@ hal_update_complete_t HAL_FLASH_End(hal_module_t* mod)
return result;
}

// Todo this code and much of the code here is duplicated between Gen2 and Gen3
// This should be factored out into directory shared by both platforms.
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
uint8_t otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
STATIC_ASSERT(sizeof(otaUpdateFlag)==DCT_OTA_UPDATE_FLAG_SIZE, "expected ota update flag size to be 1");
dct_read_app_data_copy(DCT_OTA_UPDATE_FLAG_OFFSET, &otaUpdateFlag, DCT_OTA_UPDATE_FLAG_SIZE);
hal_update_complete_t result = HAL_UPDATE_ERROR;
if (otaUpdateFlag==DCT_OTA_UPDATE_FLAG_SET) {
if (dryRun) {
// todo - we should probably check the module integrity too
// ideally this parameter would be passed to HAL_FLASH_End to avoid duplication of logic here.
result = HAL_UPDATE_APPLIED;
}
else {
// clear the flag
otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
dct_write_app_data(&otaUpdateFlag, DCT_OTA_UPDATE_FLAG_OFFSET, DCT_OTA_UPDATE_FLAG_SIZE);
result = HAL_FLASH_End(module);
}
}
return result;
}


void copy_dct(void* target, uint16_t offset, uint16_t length) {
dct_read_app_data_copy(offset, target, length);
}
Expand Down
10 changes: 9 additions & 1 deletion platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/dct.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ typedef struct __attribute__((packed)) application_dct {
uint8_t device_private_key[1216]; // sufficient for 2048 bits
uint8_t device_public_key[384]; // sufficient for 2048 bits
static_ip_config_t ip_config;
uint8_t unused[96];
uint8_t unused[95]; //
uint8_t ota_update_flag; // should be 0xA5 to trigger an update from data stored in the update region
uint32_t feature_flags[1]; // Configurable feature flags (see HAL_Feature_Set()). Default uninitialized value is 0xffffffff
uint8_t country_code[4]; // WICED country code. Stored as bit-endian format: CH1/CH2/0/rev (max 255)
uint8_t claim_code[63]; // claim code. no terminating null.
Expand Down Expand Up @@ -111,6 +112,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_SERVER_PUBLIC_KEY_OFFSET (offsetof(application_dct_t, server_public_key))
#define DCT_SERVER_ADDRESS_OFFSET ((DCT_SERVER_PUBLIC_KEY_OFFSET)+384)
#define DCT_IP_CONFIG_OFFSET (offsetof(application_dct_t, ip_config))
#define DCT_OTA_UPDATE_FLAG_OFFSET (offsetof(application_dct_t, ota_update_flag))
#define DCT_FEATURE_FLAGS_OFFSET (offsetof(application_dct_t, feature_flags))
#define DCT_COUNTRY_CODE_OFFSET (offsetof(application_dct_t, country_code))
#define DCT_CLAIM_CODE_OFFSET (offsetof(application_dct_t, claim_code))
Expand Down Expand Up @@ -138,6 +140,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_DEVICE_PUBLIC_KEY_SIZE (sizeof(application_dct_t::device_public_key))
#define DCT_SERVER_PUBLIC_KEY_SIZE (sizeof(application_dct_t::server_public_key))
#define DCT_IP_CONFIG_SIZE (sizeof(application_dct_t::ip_config))
#define DCT_OTA_UPDATE_FLAG_SIZE (sizeof(application_dct_t::ota_update_flag))
#define DCT_FEATURE_FLAGS_SIZE (sizeof(application_dct_t::feature_flags))
#define DCT_COUNTRY_CODE_SIZE (sizeof(application_dct_t::country_code))
#define DCT_CLAIM_CODE_SIZE (sizeof(application_dct_t::claim_code))
Expand Down Expand Up @@ -171,6 +174,7 @@ STATIC_ASSERT_DCT_OFFSET(version, 32);
STATIC_ASSERT_DCT_OFFSET(device_private_key, 34);
STATIC_ASSERT_DCT_OFFSET(device_public_key, 1250 /*34+1216*/);
STATIC_ASSERT_DCT_OFFSET(ip_config, 1634 /* 1250 + 384 */);
STATIC_ASSERT_DCT_OFFSET(ota_update_flag, 1753);
STATIC_ASSERT_DCT_OFFSET(feature_flags, 1754 /* 1634 + 120 */);
STATIC_ASSERT_DCT_OFFSET(country_code, 1758 /* 1754 + 4 */);
STATIC_ASSERT_DCT_OFFSET(claim_code, 1762 /* 1758 + 4 */);
Expand Down Expand Up @@ -212,6 +216,10 @@ STATIC_ASSERT_FLAGS_OFFSET(FeaturesEnabled_SysFlag, 19);
STATIC_ASSERT_FLAGS_OFFSET(RCC_CSR_SysFlag, 20);
STATIC_ASSERT_FLAGS_OFFSET(reserved, 24);

#define DCT_OTA_UPDATE_FLAG_SET (0xA5)
#define DCT_OTA_UPDATE_FLAG_CLEAR (0XFF)


// Note: This function is deprecated, use dct_read_app_data_copy() or dct_read_app_data_lock() instead
const void* dct_read_app_data(uint32_t offset);

Expand Down
9 changes: 8 additions & 1 deletion platform/MCU/nRF52840/inc/dct.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ typedef struct __attribute__((packed)) application_dct {
uint8_t device_private_key[1216]; // sufficient for 2048 bits
uint8_t device_public_key[384]; // sufficient for 2048 bits
static_ip_config_t ip_config;
uint8_t unused[96];
uint8_t unused[95];
uint8_t ota_update_flag; // should be 0xA5 to trigger an update from data stored in the update region
uint32_t feature_flags[1]; // Configurable feature flags (see HAL_Feature_Set()). Default uninitialized value is 0xffffffff
uint8_t country_code[4]; // WICED country code. Stored as bit-endian format: CH1/CH2/0/rev (max 255)
uint8_t claim_code[63]; // claim code. no terminating null.
Expand Down Expand Up @@ -118,6 +119,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_SERVER_PUBLIC_KEY_OFFSET (offsetof(application_dct_t, server_public_key))
#define DCT_SERVER_ADDRESS_OFFSET ((DCT_SERVER_PUBLIC_KEY_OFFSET)+384)
#define DCT_IP_CONFIG_OFFSET (offsetof(application_dct_t, ip_config))
#define DCT_OTA_UPDATE_FLAG_OFFSET (offsetof(application_dct_t, ota_update_flag))
#define DCT_FEATURE_FLAGS_OFFSET (offsetof(application_dct_t, feature_flags))
#define DCT_COUNTRY_CODE_OFFSET (offsetof(application_dct_t, country_code))
#define DCT_CLAIM_CODE_OFFSET (offsetof(application_dct_t, claim_code))
Expand Down Expand Up @@ -149,6 +151,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_DEVICE_PUBLIC_KEY_SIZE (sizeof(application_dct_t::device_public_key))
#define DCT_SERVER_PUBLIC_KEY_SIZE (sizeof(application_dct_t::server_public_key))
#define DCT_IP_CONFIG_SIZE (sizeof(application_dct_t::ip_config))
#define DCT_OTA_UPDATE_FLAG_SIZE (sizeof(application_dct_t::ota_update_flag))
#define DCT_FEATURE_FLAGS_SIZE (sizeof(application_dct_t::feature_flags))
#define DCT_COUNTRY_CODE_SIZE (sizeof(application_dct_t::country_code))
#define DCT_CLAIM_CODE_SIZE (sizeof(application_dct_t::claim_code))
Expand Down Expand Up @@ -178,6 +181,9 @@ typedef struct __attribute__((packed)) application_dct {
#define STATIC_ASSERT_DCT_OFFSET(field, expected) PARTICLE_STATIC_ASSERT( dct_##field, offsetof(application_dct_t, field)==expected)
#define STATIC_ASSERT_FLAGS_OFFSET(field, expected) PARTICLE_STATIC_ASSERT( dct_sysflag_##field, offsetof(platform_system_flags_t, field)==expected)

#define DCT_OTA_UPDATE_FLAG_SET (0xA5)
#define DCT_OTA_UPDATE_FLAG_CLEAR (0XFF)

/**
* Assert offsets. These ensure that the layout in flash isn't inadvertently changed.
*/
Expand All @@ -186,6 +192,7 @@ STATIC_ASSERT_DCT_OFFSET(version, 32);
STATIC_ASSERT_DCT_OFFSET(device_private_key, 34);
STATIC_ASSERT_DCT_OFFSET(device_public_key, 1250 /*34+1216*/);
STATIC_ASSERT_DCT_OFFSET(ip_config, 1634 /* 1250 + 384 */);
STATIC_ASSERT_DCT_OFFSET(ota_update_flag, 1753);
STATIC_ASSERT_DCT_OFFSET(feature_flags, 1754 /* 1634 + 120 */);
STATIC_ASSERT_DCT_OFFSET(country_code, 1758 /* 1754 + 4 */);
STATIC_ASSERT_DCT_OFFSET(claim_code, 1762 /* 1758 + 4 */);
Expand Down
8 changes: 7 additions & 1 deletion system/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,13 @@ void app_setup_and_loop(void)
bool threaded = system_thread_get_state(NULL) != spark::feature::DISABLED &&
(system_mode()!=SAFE_MODE);

Network_Setup(threaded);
if (HAL_FLASH_ApplyPendingUpdate(nullptr /*module*/, false /*dryRun*/, nullptr /*reserved*/)==HAL_UPDATE_APPLIED_PENDING_RESTART) {
// the regular OTA update delays 100 milliseconds so maintaining the same behavior.
HAL_Delay_Milliseconds(100);
HAL_Core_System_Reset_Ex(RESET_REASON_UPDATE, 0, nullptr);
}

Network_Setup(threaded); // todo - why does this come before system thread initialization?

#if PLATFORM_THREADING
if (threaded)
Expand Down
4 changes: 2 additions & 2 deletions system/src/system_update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ int Spark_Finish_Firmware_Update(FileTransfer::Descriptor& file, uint32_t flags,
if (file.store==FileTransfer::Store::FIRMWARE)
{
hal_update_complete_t result = HAL_FLASH_End(module ? (hal_module_t*)module : &mod);
system_notify_event(firmware_update, result!=HAL_UPDATE_ERROR ? firmware_update_complete : firmware_update_failed, &file);
res = (result == HAL_UPDATE_ERROR);
system_notify_event(firmware_update, result<=HAL_UPDATE_ERROR ? firmware_update_complete : firmware_update_failed, &file);
res = (result <= HAL_UPDATE_ERROR);

// always restart for now
if ((true || result==HAL_UPDATE_APPLIED_PENDING_RESTART) && !(flags & UpdateFlag::DONT_RESET))
Expand Down

0 comments on commit 55fdc11

Please sign in to comment.