[FL-2269] Core2 OTA (#1144)
* C2OTA: wip * Update Cube to 1.13.3 * Fixed prio * Functional Core2 updater * Removed hardware CRC usage; code cleanup & linter fixes * Moved hardcoded stack params to copro.mk * Fixing CI bundling of core2 fw * Removed last traces of hardcoded radio stack * OB processing draft * Python scripts cleanup * Support for comments in ob data * Sacrificed SD card icon in favor of faster update. Waiting for Storage fix * Additional handling for OB mismatched values * Description for new furi_hal apis; spelling fixes * Rework of OB write, WIP * Properly restarting OB verification loop * Split update_task_workers.c * Checking OBs after enabling post-update mode * Moved OB verification before flashing * Removed ob.data for custom stacks * Fixed progress calculation for OB * Removed unnecessary OB mask cast Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -55,7 +55,6 @@ void furi_hal_init() {
|
||||
FURI_LOG_I(TAG, "Speaker OK");
|
||||
|
||||
furi_hal_crypto_init();
|
||||
furi_hal_crc_init(true);
|
||||
|
||||
// USB
|
||||
#ifndef FURI_RAM_EXEC
|
||||
|
@@ -16,6 +16,9 @@
|
||||
#define FURI_HAL_BT_DEFAULT_MAC_ADDR \
|
||||
{ 0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72 }
|
||||
|
||||
/* Time, in ms, to wait for mode transition before crashing */
|
||||
#define C2_MODE_SWITCH_TIMEOUT 10000
|
||||
|
||||
osMutexId_t furi_hal_bt_core2_mtx = NULL;
|
||||
static FuriHalBtStack furi_hal_bt_stack = FuriHalBtStackUnknown;
|
||||
|
||||
@@ -99,7 +102,7 @@ void furi_hal_bt_unlock_core2() {
|
||||
furi_check(osMutexRelease(furi_hal_bt_core2_mtx) == osOK);
|
||||
}
|
||||
|
||||
static bool furi_hal_bt_radio_stack_is_supported(WirelessFwInfo_t* info) {
|
||||
static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) {
|
||||
bool supported = false;
|
||||
if(info->StackType == INFO_STACK_TYPE_BLE_HCI) {
|
||||
furi_hal_bt_stack = FuriHalBtStackHciLayer;
|
||||
@@ -128,21 +131,22 @@ bool furi_hal_bt_start_radio_stack() {
|
||||
}
|
||||
|
||||
do {
|
||||
// Wait until FUS is started or timeout
|
||||
WirelessFwInfo_t info = {};
|
||||
if(!ble_glue_wait_for_fus_start(&info)) {
|
||||
FURI_LOG_E(TAG, "FUS start failed");
|
||||
// Wait until C2 is started or timeout
|
||||
if(!ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)) {
|
||||
FURI_LOG_E(TAG, "Core2 start failed");
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
ble_glue_thread_stop();
|
||||
break;
|
||||
}
|
||||
// If FUS is running, start radio stack fw
|
||||
if(ble_glue_radio_stack_fw_launch_started()) {
|
||||
// If FUS is running do nothing and wait for system reset
|
||||
furi_crash("Waiting for FUS to launch radio stack firmware");
|
||||
|
||||
// If C2 is running, start radio stack fw
|
||||
if(!furi_hal_bt_ensure_c2_mode(BleGlueC2ModeStack)) {
|
||||
break;
|
||||
}
|
||||
// Check weather we support radio stack
|
||||
if(!furi_hal_bt_radio_stack_is_supported(&info)) {
|
||||
|
||||
// Check whether we support radio stack
|
||||
const BleGlueC2Info* c2_info = ble_glue_get_c2_info();
|
||||
if(!furi_hal_bt_radio_stack_is_supported(c2_info)) {
|
||||
FURI_LOG_E(TAG, "Unsupported radio stack");
|
||||
// Don't stop SHCI for crypto enclave support
|
||||
break;
|
||||
@@ -232,7 +236,7 @@ bool furi_hal_bt_change_app(FuriHalBtProfile profile, GapEventCallback event_cb,
|
||||
ble_app_thread_stop();
|
||||
gap_thread_stop();
|
||||
FURI_LOG_I(TAG, "Reset SHCI");
|
||||
SHCI_C2_Reinit();
|
||||
ble_glue_reinit_c2();
|
||||
osDelay(100);
|
||||
ble_glue_thread_stop();
|
||||
FURI_LOG_I(TAG, "Start BT initialization");
|
||||
@@ -404,3 +408,18 @@ void furi_hal_bt_stop_scan() {
|
||||
gap_stop_scan();
|
||||
}
|
||||
}
|
||||
|
||||
bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode) {
|
||||
BleGlueCommandResult fw_start_res = ble_glue_force_c2_mode(mode);
|
||||
if(fw_start_res == BleGlueCommandResultOK) {
|
||||
return true;
|
||||
} else if(fw_start_res == BleGlueCommandResultRestartPending) {
|
||||
// Do nothing and wait for system reset
|
||||
osDelay(C2_MODE_SWITCH_TIMEOUT);
|
||||
furi_crash("Waiting for FUS->radio stack transition");
|
||||
return true;
|
||||
}
|
||||
|
||||
FURI_LOG_E(TAG, "Failed to switch C2 mode: %d", fw_start_res);
|
||||
return false;
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ void furi_hal_crc_init(bool synchronize) {
|
||||
void furi_hal_crc_reset() {
|
||||
furi_check(hal_crc_control.state == CRC_State_Ready);
|
||||
if(hal_crc_control.mtx) {
|
||||
furi_check(osMutexGetOwner(hal_crc_control.mtx) == osThreadGetId());
|
||||
osMutexRelease(hal_crc_control.mtx);
|
||||
}
|
||||
LL_CRC_ResetCRCCalculationUnit(CRC);
|
||||
@@ -84,5 +85,9 @@ uint32_t furi_hal_crc_feed(void* data, uint16_t length) {
|
||||
|
||||
bool furi_hal_crc_acquire(uint32_t timeout) {
|
||||
furi_assert(hal_crc_control.mtx);
|
||||
return osMutexAcquire(hal_crc_control.mtx, timeout) == osOK;
|
||||
if(osMutexAcquire(hal_crc_control.mtx, timeout) == osOK) {
|
||||
LL_CRC_ResetCRCCalculationUnit(CRC);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -6,7 +6,8 @@
|
||||
|
||||
#include <stm32wbxx.h>
|
||||
|
||||
#define FURI_HAL_TAG "FuriHalFlash"
|
||||
#define TAG "FuriHalFlash"
|
||||
|
||||
#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail"
|
||||
#define FURI_HAL_FLASH_READ_BLOCK 8
|
||||
#define FURI_HAL_FLASH_WRITE_BLOCK 8
|
||||
@@ -14,13 +15,17 @@
|
||||
#define FURI_HAL_FLASH_CYCLES_COUNT 10000
|
||||
#define FURI_HAL_FLASH_TIMEOUT 1000
|
||||
#define FURI_HAL_FLASH_KEY1 0x45670123U
|
||||
|
||||
#define FURI_HAL_FLASH_KEY2 0xCDEF89ABU
|
||||
#define FURI_HAL_FLASH_TOTAL_PAGES 256
|
||||
#define FURI_HAL_FLASH_SR_ERRORS \
|
||||
(FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR | FLASH_SR_PGAERR | FLASH_SR_SIZERR | \
|
||||
FLASH_SR_PGSERR | FLASH_SR_MISERR | FLASH_SR_FASTERR | FLASH_SR_RDERR | FLASH_SR_OPTVERR)
|
||||
|
||||
//#define FURI_HAL_FLASH_OB_START_ADDRESS 0x1FFF8000
|
||||
#define FURI_HAL_FLASH_OPT_KEY1 0x08192A3B
|
||||
#define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F
|
||||
#define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2))
|
||||
|
||||
#define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL))
|
||||
#define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
|
||||
(((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \
|
||||
@@ -88,7 +93,7 @@ static void furi_hal_flash_unlock() {
|
||||
WRITE_REG(FLASH->KEYR, FURI_HAL_FLASH_KEY1);
|
||||
WRITE_REG(FLASH->KEYR, FURI_HAL_FLASH_KEY2);
|
||||
|
||||
/* verify Flash is unlock */
|
||||
/* verify Flash is unlocked */
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_LOCK) == 0U);
|
||||
}
|
||||
|
||||
@@ -386,4 +391,125 @@ int16_t furi_hal_flash_get_page_number(size_t address) {
|
||||
}
|
||||
|
||||
return (address - flash_base) / FURI_HAL_FLASH_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t furi_hal_flash_ob_get_word(size_t word_idx, bool complementary) {
|
||||
furi_check(word_idx <= FURI_HAL_FLASH_OB_TOTAL_WORDS);
|
||||
const uint32_t* ob_data = (const uint32_t*)(OPTION_BYTE_BASE);
|
||||
size_t raw_word_idx = word_idx * 2;
|
||||
if(complementary) {
|
||||
raw_word_idx += 1;
|
||||
}
|
||||
return ob_data[raw_word_idx];
|
||||
}
|
||||
|
||||
void furi_hal_flash_ob_unlock() {
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0U);
|
||||
furi_hal_flash_begin(true);
|
||||
WRITE_REG(FLASH->OPTKEYR, FURI_HAL_FLASH_OPT_KEY1);
|
||||
__ISB();
|
||||
WRITE_REG(FLASH->OPTKEYR, FURI_HAL_FLASH_OPT_KEY2);
|
||||
/* verify OB area is unlocked */
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0U);
|
||||
}
|
||||
|
||||
void furi_hal_flash_ob_lock() {
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0U);
|
||||
SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);
|
||||
furi_hal_flash_end(true);
|
||||
furi_check(READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0U);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FuriHalFlashObInvalid,
|
||||
FuriHalFlashObRegisterUserRead,
|
||||
FuriHalFlashObRegisterPCROP1AStart,
|
||||
FuriHalFlashObRegisterPCROP1AEnd,
|
||||
FuriHalFlashObRegisterWRPA,
|
||||
FuriHalFlashObRegisterWRPB,
|
||||
FuriHalFlashObRegisterPCROP1BStart,
|
||||
FuriHalFlashObRegisterPCROP1BEnd,
|
||||
FuriHalFlashObRegisterIPCCMail,
|
||||
FuriHalFlashObRegisterSecureFlash,
|
||||
FuriHalFlashObRegisterC2Opts,
|
||||
} FuriHalFlashObRegister;
|
||||
|
||||
typedef struct {
|
||||
FuriHalFlashObRegister ob_reg;
|
||||
uint32_t* ob_register_address;
|
||||
} FuriHalFlashObMapping;
|
||||
|
||||
#define OB_REG_DEF(INDEX, REG) \
|
||||
{ .ob_reg = INDEX, .ob_register_address = (uint32_t*)(REG) }
|
||||
|
||||
static const FuriHalFlashObMapping furi_hal_flash_ob_reg_map[FURI_HAL_FLASH_OB_TOTAL_WORDS] = {
|
||||
OB_REG_DEF(FuriHalFlashObRegisterUserRead, (&FLASH->OPTR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1AStart, (&FLASH->PCROP1ASR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1AEnd, (&FLASH->PCROP1AER)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterWRPA, (&FLASH->WRP1AR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterWRPB, (&FLASH->WRP1BR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1BStart, (&FLASH->PCROP1BSR)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterPCROP1BEnd, (&FLASH->PCROP1BER)),
|
||||
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObInvalid, (NULL)),
|
||||
|
||||
OB_REG_DEF(FuriHalFlashObRegisterIPCCMail, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterSecureFlash, (NULL)),
|
||||
OB_REG_DEF(FuriHalFlashObRegisterC2Opts, (NULL)),
|
||||
};
|
||||
|
||||
void furi_hal_flash_ob_apply() {
|
||||
furi_hal_flash_ob_unlock();
|
||||
/* OBL_LAUNCH: When set to 1, this bit forces the option byte reloading.
|
||||
* It cannot be written if OPTLOCK is set */
|
||||
SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);
|
||||
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
|
||||
furi_hal_flash_ob_lock();
|
||||
}
|
||||
|
||||
bool furi_hal_flash_ob_set_word(size_t word_idx, const uint32_t value) {
|
||||
furi_check(word_idx < FURI_HAL_FLASH_OB_TOTAL_WORDS);
|
||||
|
||||
const FuriHalFlashObMapping* reg_def = &furi_hal_flash_ob_reg_map[word_idx];
|
||||
if(reg_def->ob_register_address == NULL) {
|
||||
FURI_LOG_E(TAG, "Attempt to set RO OB word %d", word_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Setting OB reg %d for word %d (addr 0x%08X) to 0x%08X",
|
||||
reg_def->ob_reg,
|
||||
word_idx,
|
||||
reg_def->ob_register_address,
|
||||
value);
|
||||
|
||||
/* 1. Clear OPTLOCK option lock bit with the clearing sequence */
|
||||
furi_hal_flash_ob_unlock();
|
||||
|
||||
/* 2. Write the desired options value in the options registers */
|
||||
*reg_def->ob_register_address = value;
|
||||
|
||||
/* 3. Check that no Flash memory operation is on going by checking the BSY && PESD */
|
||||
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
|
||||
while(LL_FLASH_IsActiveFlag_OperationSuspended()) {
|
||||
osThreadYield();
|
||||
};
|
||||
|
||||
/* 4. Set the Options start bit OPTSTRT */
|
||||
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
|
||||
|
||||
/* 5. Wait for the BSY bit to be cleared. */
|
||||
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
|
||||
furi_hal_flash_ob_lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
const FuriHalFlashRawOptionByteData* furi_hal_flash_ob_get_raw_ptr() {
|
||||
return (const FuriHalFlashRawOptionByteData*)OPTION_BYTE_BASE;
|
||||
}
|
||||
|
@@ -4,6 +4,25 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define FURI_HAL_FLASH_OB_RAW_SIZE_BYTES 0x80
|
||||
#define FURI_HAL_FLASH_OB_SIZE_WORDS (FURI_HAL_FLASH_OB_RAW_SIZE_BYTES / sizeof(uint32_t))
|
||||
#define FURI_HAL_FLASH_OB_TOTAL_VALUES (FURI_HAL_FLASH_OB_SIZE_WORDS / 2)
|
||||
|
||||
typedef union {
|
||||
uint8_t bytes[FURI_HAL_FLASH_OB_RAW_SIZE_BYTES];
|
||||
union {
|
||||
struct {
|
||||
uint32_t base;
|
||||
uint32_t complementary_value;
|
||||
} values;
|
||||
uint64_t dword;
|
||||
} obs[FURI_HAL_FLASH_OB_TOTAL_VALUES];
|
||||
} FuriHalFlashRawOptionByteData;
|
||||
|
||||
_Static_assert(
|
||||
sizeof(FuriHalFlashRawOptionByteData) == FURI_HAL_FLASH_OB_RAW_SIZE_BYTES,
|
||||
"UpdateManifestOptionByteData size error");
|
||||
|
||||
/** Init flash, applying necessary workarounds
|
||||
*/
|
||||
void furi_hal_flash_init();
|
||||
@@ -64,7 +83,7 @@ size_t furi_hal_flash_get_free_page_count();
|
||||
|
||||
/** Erase Flash
|
||||
*
|
||||
* @warning locking operation with critical section, stales execution
|
||||
* @warning locking operation with critical section, stalls execution
|
||||
*
|
||||
* @param page The page to erase
|
||||
*
|
||||
@@ -74,7 +93,7 @@ bool furi_hal_flash_erase(uint8_t page);
|
||||
|
||||
/** Write double word (64 bits)
|
||||
*
|
||||
* @warning locking operation with critical section, stales execution
|
||||
* @warning locking operation with critical section, stalls execution
|
||||
*
|
||||
* @param address destination address, must be double word aligned.
|
||||
* @param data data to write
|
||||
@@ -85,7 +104,7 @@ bool furi_hal_flash_write_dword(size_t address, uint64_t data);
|
||||
|
||||
/** Write aligned page data (up to page size)
|
||||
*
|
||||
* @warning locking operation with critical section, stales execution
|
||||
* @warning locking operation with critical section, stalls execution
|
||||
*
|
||||
* @param address destination address, must be page aligned.
|
||||
* @param data data to write
|
||||
@@ -99,5 +118,27 @@ bool furi_hal_flash_program_page(const uint8_t page, const uint8_t* data, uint16
|
||||
*
|
||||
* @return page number, -1 for invalid address
|
||||
*/
|
||||
int16_t furi_hal_flash_get_page_number(size_t address);
|
||||
|
||||
int16_t furi_hal_flash_get_page_number(size_t address);
|
||||
/** Writes OB word, using non-compl. index of register in Flash, OPTION_BYTE_BASE
|
||||
*
|
||||
* @warning locking operation with critical section, stalls execution
|
||||
*
|
||||
* @param word_idx OB word number
|
||||
* @param value data to write
|
||||
* @return true if value was written, false for read-only word
|
||||
*/
|
||||
bool furi_hal_flash_ob_set_word(size_t word_idx, const uint32_t value);
|
||||
|
||||
/** Forces a reload of OB data from flash to registers
|
||||
*
|
||||
* @warning Initializes system restart
|
||||
*
|
||||
*/
|
||||
void furi_hal_flash_ob_apply();
|
||||
|
||||
/** Get raw OB storage data
|
||||
*
|
||||
* @return pointer to read-only data of OB (raw + complementary values)
|
||||
*/
|
||||
const FuriHalFlashRawOptionByteData* furi_hal_flash_ob_get_raw_ptr();
|
||||
|
@@ -66,44 +66,45 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) {
|
||||
out("firmware_target", string_get_cstr(value), false, context);
|
||||
}
|
||||
|
||||
WirelessFwInfo_t pWirelessInfo;
|
||||
if(furi_hal_bt_is_alive() && SHCI_GetWirelessFwInfo(&pWirelessInfo) == SHCI_Success) {
|
||||
if(furi_hal_bt_is_alive()) {
|
||||
const BleGlueC2Info* ble_c2_info = ble_glue_get_c2_info();
|
||||
out("radio_alive", "true", false, context);
|
||||
out("radio_mode", ble_c2_info->mode == BleGlueC2ModeFUS ? "FUS" : "Stack", false, context);
|
||||
|
||||
// FUS Info
|
||||
string_printf(value, "%d", pWirelessInfo.FusVersionMajor);
|
||||
string_printf(value, "%d", ble_c2_info->FusVersionMajor);
|
||||
out("radio_fus_major", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%d", pWirelessInfo.FusVersionMinor);
|
||||
string_printf(value, "%d", ble_c2_info->FusVersionMinor);
|
||||
out("radio_fus_minor", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%d", pWirelessInfo.FusVersionSub);
|
||||
string_printf(value, "%d", ble_c2_info->FusVersionSub);
|
||||
out("radio_fus_sub", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%dK", pWirelessInfo.FusMemorySizeSram2B);
|
||||
string_printf(value, "%dK", ble_c2_info->FusMemorySizeSram2B);
|
||||
out("radio_fus_sram2b", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%dK", pWirelessInfo.FusMemorySizeSram2A);
|
||||
string_printf(value, "%dK", ble_c2_info->FusMemorySizeSram2A);
|
||||
out("radio_fus_sram2a", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%dK", pWirelessInfo.FusMemorySizeFlash * 4);
|
||||
string_printf(value, "%dK", ble_c2_info->FusMemorySizeFlash * 4);
|
||||
out("radio_fus_flash", string_get_cstr(value), false, context);
|
||||
|
||||
// Stack Info
|
||||
string_printf(value, "%d", pWirelessInfo.StackType);
|
||||
string_printf(value, "%d", ble_c2_info->StackType);
|
||||
out("radio_stack_type", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%d", pWirelessInfo.VersionMajor);
|
||||
string_printf(value, "%d", ble_c2_info->VersionMajor);
|
||||
out("radio_stack_major", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%d", pWirelessInfo.VersionMinor);
|
||||
string_printf(value, "%d", ble_c2_info->VersionMinor);
|
||||
out("radio_stack_minor", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%d", pWirelessInfo.VersionSub);
|
||||
string_printf(value, "%d", ble_c2_info->VersionSub);
|
||||
out("radio_stack_sub", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%d", pWirelessInfo.VersionBranch);
|
||||
string_printf(value, "%d", ble_c2_info->VersionBranch);
|
||||
out("radio_stack_branch", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%d", pWirelessInfo.VersionReleaseType);
|
||||
string_printf(value, "%d", ble_c2_info->VersionReleaseType);
|
||||
out("radio_stack_release", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%dK", pWirelessInfo.MemorySizeSram2B);
|
||||
string_printf(value, "%dK", ble_c2_info->MemorySizeSram2B);
|
||||
out("radio_stack_sram2b", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%dK", pWirelessInfo.MemorySizeSram2A);
|
||||
string_printf(value, "%dK", ble_c2_info->MemorySizeSram2A);
|
||||
out("radio_stack_sram2a", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%dK", pWirelessInfo.MemorySizeSram1);
|
||||
string_printf(value, "%dK", ble_c2_info->MemorySizeSram1);
|
||||
out("radio_stack_sram1", string_get_cstr(value), false, context);
|
||||
string_printf(value, "%dK", pWirelessInfo.MemorySizeFlash * 4);
|
||||
string_printf(value, "%dK", ble_c2_info->MemorySizeFlash * 4);
|
||||
out("radio_stack_flash", string_get_cstr(value), false, context);
|
||||
|
||||
// Mac address
|
||||
|
@@ -64,7 +64,7 @@ void furi_hal_vcp_init() {
|
||||
vcp->rx_stream = xStreamBufferCreate(VCP_RX_BUF_SIZE, 1);
|
||||
|
||||
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
|
||||
FURI_LOG_W(TAG, "Skipped worker init: device in special startup mode=");
|
||||
FURI_LOG_W(TAG, "Skipped worker init: device in special startup mode");
|
||||
return;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user