Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: nrf_modem: init once on dfu apply #105

Merged
merged 3 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions applications/asset_tracker_v2/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,41 +174,48 @@ static void sub_state_set(enum sub_state_type new_state)
}

#if defined(CONFIG_NRF_MODEM_LIB)
/* Check the return code from nRF modem library initialization to ensure that
* the modem is rebooted if a modem firmware update is ready to be applied or
* an error condition occurred during firmware update or library initialization.
*/
static void modem_init(void)
{
int ret = nrf_modem_lib_init();

/* Handle return values relating to modem firmware update */
switch (ret) {
case 0:
/* Initialization successful, no action required. */
return;
static void on_modem_lib_dfu(int dfu_res, void *ctx)
{
switch (dfu_res) {
case NRF_MODEM_DFU_RESULT_OK:
LOG_DBG("MODEM UPDATE OK. Will run new modem firmware after reboot");
break;
LOG_DBG("nRF Modem firmware update succeeded");
/* Fallthrough */
case NRF_MODEM_DFU_RESULT_UUID_ERROR:
case NRF_MODEM_DFU_RESULT_AUTH_ERROR:
LOG_ERR("MODEM UPDATE ERROR %d. Will run old firmware", ret);
LOG_ERR("MODEM UPDATE ERROR 0x%x. Running old firmware", dfu_res);
break;
case NRF_MODEM_DFU_RESULT_HARDWARE_ERROR:
case NRF_MODEM_DFU_RESULT_INTERNAL_ERROR:
LOG_ERR("MODEM UPDATE FATAL ERROR %d. Modem failure", ret);
LOG_ERR("MODEM UPDATE FATAL ERROR 0x%x. Modem failure", dfu_res);
break;
case NRF_MODEM_DFU_RESULT_VOLTAGE_LOW:
LOG_ERR("MODEM UPDATE CANCELLED %d.", ret);
LOG_ERR("MODEM UPDATE CANCELLED 0x%x.", dfu_res);
LOG_ERR("Please reboot once you have sufficient power for the DFU");
break;
default:
/* All non-zero return codes other than DFU result codes are
* considered irrecoverable and a reboot is needed.
*/
LOG_ERR("nRF modem lib initialization failed, error: %d", ret);
/* Unknown DFU result code */
LOG_ERR("nRF modem DFU failed, error: 0x%x", dfu_res);
break;
}
}

NRF_MODEM_LIB_ON_DFU_RES(main_dfu_hook, on_modem_lib_dfu, NULL);

/* Check the return code from nRF modem library initialization to ensure that
* the modem is rebooted or an error condition occurred during library initialization.
*/
static void modem_init(void)
{
int ret;

ret = nrf_modem_lib_init();
if (ret == 0) {
LOG_DBG("nRF Modem Library initialized successfully");
return;
}

LOG_ERR("nRF modem lib initialization failed, error: %d", ret);

#if defined(CONFIG_NRF_CLOUD_FOTA)
/* Ignore return value, rebooting below */
Expand Down
54 changes: 21 additions & 33 deletions applications/serial_lte_modem/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ static void indicate_wk(struct k_work *work);

BUILD_ASSERT(CONFIG_SLM_WAKEUP_PIN >= 0, "Wake up pin not configured");

NRF_MODEM_LIB_ON_DFU_RES(main_dfu_hook, nrf_modem_on_dfu_res, NULL);

#if defined(CONFIG_NRF_MODEM_LIB_ON_FAULT_APPLICATION_SPECIFIC)
static void on_modem_failure_shutdown(struct k_work *item);
static void on_modem_failure_reinit(struct k_work *item);
Expand Down Expand Up @@ -244,54 +246,40 @@ void enter_shutdown(void)
nrf_regulators_system_off(NRF_REGULATORS_NS);
}

bool handle_nrf_modem_lib_init_ret(int ret)
static void nrf_modem_on_dfu_res(int dfu_res, void *ctx)
{
switch (ret) {
case 0:
return false; /* Initialization successful, no action required. */
switch (dfu_res) {
case NRF_MODEM_DFU_RESULT_OK:
LOG_INF("MODEM UPDATE OK. Will run new firmware");
LOG_INF("nRF Modem firmware update succeeded");
fota_stage = FOTA_STAGE_COMPLETE;
fota_status = FOTA_STATUS_OK;
fota_info = 0;
break;
case NRF_MODEM_DFU_RESULT_UUID_ERROR:
case NRF_MODEM_DFU_RESULT_AUTH_ERROR:
LOG_ERR("MODEM UPDATE ERROR %d. Will run old firmware", ret);
LOG_ERR("MODEM UPDATE ERROR 0x%x. Running old firmware", dfu_res);
fota_status = FOTA_STATUS_ERROR;
fota_info = ret;
fota_info = dfu_res;
break;
case NRF_MODEM_DFU_RESULT_HARDWARE_ERROR:
case NRF_MODEM_DFU_RESULT_INTERNAL_ERROR:
LOG_ERR("MODEM UPDATE FATAL ERROR %d. Modem failure", ret);
LOG_ERR("MODEM UPDATE FATAL ERROR 0x%x", dfu_res);
LOG_ERR("Please program full modem firmware with the bootloader or external tools");
fota_status = FOTA_STATUS_ERROR;
fota_info = ret;
fota_info = dfu_res;
break;
case NRF_MODEM_DFU_RESULT_VOLTAGE_LOW:
LOG_ERR("MODEM UPDATE CANCELLED %d.", ret);
LOG_ERR("MODEM UPDATE CANCELLED 0x%x.", dfu_res);
LOG_ERR("Please reboot once you have sufficient power for the DFU");
fota_stage = FOTA_STAGE_ACTIVATE;
fota_status = FOTA_STATUS_ERROR;
fota_info = ret;
fota_info = dfu_res;
break;
default:
if (ret >= 0) {
LOG_WRN("Unhandled nrf_modem_lib_init() return code %d.", ret);
break;
}
/* All non-zero return codes other than DFU result codes are
* considered irrecoverable and a reboot is needed.
*/
LOG_ERR("nRF modem lib initialization failed, error: %d", ret);
LOG_ERR("Unknown DFU result: 0x%x", dfu_res);
fota_status = FOTA_STATUS_ERROR;
fota_info = ret;
slm_settings_fota_save();
LOG_WRN("Rebooting...");
LOG_PANIC();
sys_reboot(SYS_REBOOT_COLD);
break;
fota_info = dfu_res;
}
return true;
}

static void handle_mcuboot_swap_ret(void)
Expand Down Expand Up @@ -379,20 +367,20 @@ int main(void)
LOG_WRN("Failed to init slm settings");
}

const int ret = nrf_modem_lib_init();

int ret = nrf_modem_lib_init();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly that nrf_modem_on_dfu_res() will get called right before nrf_modem_lib_init() returns?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, or rather, right before nrf_modem_init() returns to nrf_modem_lib_init(), so the NRF_MODEM_LIB_ON_INIT hooks are called after.

if (ret < 0) {
LOG_ERR("Modem library init failed, err: %d", ret);
return ret;
if (ret != -EAGAIN) {
tomi-font marked this conversation as resolved.
Show resolved Hide resolved
LOG_ERR("Please program full modem firmware with the bootloader or "
"external tools");
}
}

/* Post-FOTA handling */
if (fota_stage != FOTA_STAGE_INIT) {
if (fota_type == DFU_TARGET_IMAGE_TYPE_MODEM_DELTA) {
slm_finish_modem_fota(ret);
} else if (fota_type == DFU_TARGET_IMAGE_TYPE_MCUBOOT) {
if (fota_type == DFU_TARGET_IMAGE_TYPE_MCUBOOT) {
handle_mcuboot_swap_ret();
} else {
} else if (fota_type != DFU_TARGET_IMAGE_TYPE_MODEM_DELTA) {
LOG_ERR("Unknown DFU type: %d", fota_type);
fota_status = FOTA_STATUS_ERROR;
fota_info = -EAGAIN;
Expand Down
13 changes: 7 additions & 6 deletions applications/serial_lte_modem/src/slm_at_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,18 @@ static int handle_at_modemreset(enum at_cmd_type type)
++step;

ret = nrf_modem_lib_init();

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be good to add a small comment saying that nrf_modem_on_dfu_res() will get indirectly called to help follow the logic of the fota_* variables (which was already messy).

/* nrf_modem_dfu_res() is called in nrf_modem_lib_init with the DFU result. */
if ((fota_stage != FOTA_STAGE_INIT &&
fota_type == DFU_TARGET_IMAGE_TYPE_MODEM_DELTA)) {
slm_fota_post_process();
}

if (ret < 0) {
break;
}
++step;

if (ret > 0 || (fota_stage != FOTA_STAGE_INIT
&& fota_type == DFU_TARGET_IMAGE_TYPE_MODEM_DELTA)) {
slm_finish_modem_fota(ret);
slm_fota_post_process();
}

/* Success. */
rsp_send("\r\n#XMODEMRESET: 0\r\n");
return 0;
Expand Down
27 changes: 0 additions & 27 deletions applications/serial_lte_modem/src/slm_at_fota.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,30 +372,3 @@ void slm_fota_post_process(void)
slm_settings_fota_save();
}
}

void slm_finish_modem_fota(int modem_lib_init_ret)
{
if (handle_nrf_modem_lib_init_ret(modem_lib_init_ret)) {
char buf[40];

LOG_INF("Re-initializing the modem due to"
" ongoing modem firmware update.");

/* The second init needs to be done regardless of the return value.
* Refer to the below link for more information on the procedure.
* https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/nrf_modem/doc/delta_dfu.html#reinitializing-the-modem-to-run-the-new-firmware
*/
modem_lib_init_ret = nrf_modem_lib_init();
handle_nrf_modem_lib_init_ret(modem_lib_init_ret);

nrf_modem_at_cmd(buf, sizeof(buf), "%s", "AT%SHORTSWVER");
if (strstr(buf, "1.3.4") || strstr(buf, "1.3.5")) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this has been removed already by nrfconnect#12086.
This branch/repo is not quite up to date with NCS's main.

/* Those versions suffer from a bug that provokes UICC failure (+CEREG: 90)
* after the update, preventing the modem from registering to the network.
*/
LOG_INF("Applying the workaround to a modem firmware update issue...");
nrf_modem_lib_shutdown();
nrf_modem_lib_init();
}
}
}
16 changes: 0 additions & 16 deletions applications/serial_lte_modem/src/slm_at_fota.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,5 @@ int slm_at_fota_uninit(void);
*/
void slm_fota_post_process(void);

/**
* @brief Finishes the modem firmware update.
*
* This is to be called after the application or modem
* has been rebooted and a modem firmware update is ongoing.
*/
void slm_finish_modem_fota(int modem_lib_init_ret);

/**
* @brief Handles @ref nrf_modem_lib_init() return values
* relating to modem firmware update.
*
* @return Whether the modem must be re-initialized.
*/
bool handle_nrf_modem_lib_init_ret(int modem_lib_init_ret);

/** @} */
#endif /* SLM_AT_FOTA_ */
61 changes: 58 additions & 3 deletions include/modem/nrf_modem_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,20 @@ extern "C" {
* Use @ref nrf_modem_lib_init() to initialize in normal mode and
* @ref nrf_modem_lib_bootloader_init() to initialize the Modem library in bootloader mode.
*
* @return int Zero on success, a positive value @em nrf_modem_dfu when executing
* Modem firmware updates, and negative errno on other failures.
* @retval Zero on success.
*
* @retval -NRF_EPERM The Modem library is already initialized.
* @retval -NRF_EFAULT @c init_params is @c NULL.
* @retval -NRF_ENOLCK Not enough semaphores.
* @retval -NRF_ENOMEM Not enough shared memory.
* @retval -NRF_EINVAL Control region size is incorrect or missing handlers in @c init_params.
* @retval -NRF_ENOTSUPP RPC version mismatch.
* @retval -NRF_ETIMEDOUT Operation timed out.
* @retval -NRF_ACCESS Modem firmware authentication failure.
* @retval -NRF_EAGAIN Modem device firmware upgrade failure.
* DFU is scheduled at next initialization.
* @retval -NRF_EIO Modem device firmware upgrade failure.
* Reprogramming the modem firmware is necessary to recover.
*/
int nrf_modem_lib_init(void);

Expand All @@ -54,7 +66,17 @@ int nrf_modem_lib_init(void);
* Use @ref nrf_modem_lib_init() to initialize in normal mode and
* @ref nrf_modem_lib_bootloader_init() to initialize the Modem library in bootloader mode.
*
* @return int Zero on success, non-zero otherwise.
* @retval Zero on success.
*
* @retval -NRF_EPERM The Modem library is already initialized.
* @retval -NRF_EFAULT @c init_params is @c NULL.
* @retval -NRF_ENOLCK Not enough semaphores.
* @retval -NRF_ENOMEM Not enough shared memory.
* @retval -NRF_EINVAL Missing handler in @c init_params.
* @retval -NRF_EACCES Bad root digest.
* @retval -NRF_ETIMEDOUT Operation timed out.
* @retval -NRF_EIO Bootloader fault.
* @retval -NRF_ENOSYS Operation not available.
*/
int nrf_modem_lib_bootloader_init(void);

Expand All @@ -67,6 +89,20 @@ int nrf_modem_lib_bootloader_init(void);
*/
int nrf_modem_lib_shutdown(void);

/**
* @brief Modem library dfu callback struct.
*/
struct nrf_modem_lib_dfu_cb {
/**
* @brief Callback function.
* @param dfu_res The return value of nrf_modem_init()
* @param ctx User-defined context
*/
void (*callback)(int dfu_res, void *ctx);
/** User defined context */
void *context;
};

/**
* @brief Modem library initialization callback struct.
*/
Expand Down Expand Up @@ -94,6 +130,25 @@ struct nrf_modem_lib_shutdown_cb {
void *context;
};

/**
* @brief Define a callback for DFU result @ref nrf_modem_lib_init calls.
*
* The callback function @p _callback is invoked after the library has been initialized.
*
* @note The @c NRF_MODEM_LIB_ON_DFU_RES callback can be used to subscribe to the result of a modem
* DFU operation.
*
* @param name Callback name
* @param _callback Callback function name
* @param _context User-defined context for the callback
*/
#define NRF_MODEM_LIB_ON_DFU_RES(name, _callback, _context) \
static void _callback(int dfu_res, void *ctx); \
STRUCT_SECTION_ITERABLE(nrf_modem_lib_dfu_cb, nrf_modem_dfu_hook_##name) = { \
.callback = _callback, \
.context = _context, \
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nrf_modem_lib_init()'s description probably has to be updated (at least regarding the return values)?

/**
* @brief Define a callback for @ref nrf_modem_lib_init calls.
*
Expand Down
Loading