Skip to content

Commit

Permalink
Implements background modem update checks, Cellular.updateStatus(), C…
Browse files Browse the repository at this point in the history
…ellular.enableUpdates()
  • Loading branch information
technobly committed Oct 6, 2021
1 parent 672130c commit 0e2f5db
Show file tree
Hide file tree
Showing 14 changed files with 387 additions and 252 deletions.
10 changes: 10 additions & 0 deletions hal/inc/cellular_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ int cellular_start_ncp_firmware_update(bool update = false, void* reserved = NUL
*/
int cellular_get_ublox_firmware_version(uint32_t* version, void* reserved = NULL);

/**
* Get modem firmware update status result
*/
int cellular_update_status(void* reserved = NULL);

/**
* Enable modem firmware updates (blocking call, requires a pending update)
*/
int cellular_enable_updates(void* reserved = NULL);

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 2 additions & 0 deletions hal/inc/hal_dynalib_cellular.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ DYNALIB_FN(BASE_CELL_IDX + 3, hal_cellular, cellular_powered, bool(void*))
#endif // !HAL_PLATFORM_NCP

DYNALIB_FN(BASE_CELL_IDX1 + 0, hal_cellular, cellular_urcs, cellular_result_t(bool, void*))
DYNALIB_FN(BASE_CELL_IDX1 + 1, hal_cellular, cellular_update_status, int(void*))
DYNALIB_FN(BASE_CELL_IDX1 + 2, hal_cellular, cellular_enable_updates, int(void*))

DYNALIB_END(hal_cellular)

Expand Down
16 changes: 16 additions & 0 deletions hal/network/ncp/cellular/cellular_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "cellular_enums_hal.h"
#include "cellular_ncp_dev_mapping.h"

#include "ncp_fw_update.h"

#include <limits>

namespace {
Expand Down Expand Up @@ -618,4 +620,18 @@ int cellular_get_ublox_firmware_version(uint32_t* version, void* reserved) {
return SYSTEM_ERROR_NONE;
}

int cellular_update_status(void* reserved) {
#if HAL_PLATFORM_NCP_FW_UPDATE
return services::NcpFwUpdate::instance()->updateStatus();
#else
return false;
#endif
}

int cellular_enable_updates(void* reserved) {
#if HAL_PLATFORM_NCP_FW_UPDATE
return services::NcpFwUpdate::instance()->enableUpdates();
#else
return SYSTEM_ERROR_NOT_SUPPORTED;
#endif
}
12 changes: 9 additions & 3 deletions hal/network/ncp_client/sara/sara_ncp_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ LOG_SOURCE_CATEGORY("ncp.client");
#include <lwip/memp.h>
#include "enumclass.h"

#include "ncp_fw_update.h"

#undef LOG_COMPILE_TIME_LEVEL
#define LOG_COMPILE_TIME_LEVEL LOG_LEVEL_ALL

Expand Down Expand Up @@ -1501,7 +1503,6 @@ int SaraNcpClient::getUbloxFirmwareVersion(uint32_t* version) {
char atResponse[64] = {};
auto resp = parser_.sendCommand("ATI9");
CHECK_PARSER(resp.readLine(atResponse, sizeof(atResponse)));
LOG(INFO, "atResponse:[%s]", atResponse);
if (::sscanf(atResponse, "%*[\r\nL0.0.00.00.]%d.%d%*[,A.]%d.%d", &major1, &minor1, &major2, &minor2) == 4) {
ver = major1 * 1000000 + minor1 * 10000 + major2 * 100 + minor2;
} else if (::sscanf(atResponse, "%*[\r\nL0.0.00.00.]%d.%d%8[^,]%*[,A.]%d.%d", &major1, &minor1, eng, &major2, &minor2) == 5) {
Expand All @@ -1524,11 +1525,16 @@ int SaraNcpClient::initReady(ModemState state) {
if (getUbloxFirmwareVersion(&fwVersion_) != SYSTEM_ERROR_NONE) {
fwVersion_ = 0;
}
CHECK_TRUE(fwVersion_ != 0, SYSTEM_ERROR_AT_RESPONSE_UNEXPECTED); // XXX: The modem may get into a bad state without knowing what version we are operating with
#if HAL_PLATFORM_NCP_FW_UPDATE
if (ncpId() == PLATFORM_NCP_SARA_R510) {
CHECK(services::NcpFwUpdate::instance()->checkUpdate(fwVersion_));
}
#endif

// L0.0.00.00.05.06,A.02.00 has a memory issue
R410MemoryIssuePresent_ = (ncpId() == PLATFORM_NCP_SARA_R410) ? (fwVersion_ == UBLOX_NCP_R4_APP_FW_VERSION_MEMORY_LEAK_ISSUE) : false;
R410OldFirmwarePresent_ = (ncpId() == PLATFORM_NCP_SARA_R410) ? (fwVersion_ < UBLOX_NCP_R4_APP_FW_VERSION_LATEST_02B_01) : false;
R410OldFirmwarePresent_ = (ncpId() == PLATFORM_NCP_SARA_R410) ? (fwVersion_ >= UBLOX_NCP_R4_APP_FW_VERSION_MEMORY_LEAK_ISSUE &&
fwVersion_ < UBLOX_NCP_R4_APP_FW_VERSION_LATEST_02B_01) : false;
// Select either internal or external SIM card slot depending on the configuration
CHECK(selectSimCard(state));
// Make sure flow control is enabled as well
Expand Down
8 changes: 8 additions & 0 deletions hal/src/electron/cellular_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,4 +458,12 @@ int cellular_start_ncp_firmware_update(bool update, void* reserved) {
return SYSTEM_ERROR_NOT_SUPPORTED;
}

int cellular_update_status(void* reserved) {
return SYSTEM_ERROR_NOT_SUPPORTED;
}

int cellular_enable_updates(void* reserved) {
return SYSTEM_ERROR_NOT_SUPPORTED;
}

#endif // !defined(HAL_CELLULAR_EXCLUDE)
4 changes: 2 additions & 2 deletions hal/src/stm32f2xx/core_hal_stm32f2xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1220,10 +1220,10 @@ int HAL_Feature_Set(HAL_Feature feature, bool enabled)
return Write_Feature_Flag(FEATURE_FLAG_LED_OVERRIDDEN, !enabled, NULL);
}
#if HAL_PLATFORM_INTERNAL_LOW_SPEED_CLOCK
case FEATURE_DISABLE_EXTERNAL_LOW_SPEED_CLOCK: {
case FEATURE_DISABLE_EXTERNAL_LOW_SPEED_CLOCK: {
uint32_t value = enabled ? DCT_EXT_LOW_SPEED_CLOCK_DISABLE_SET : DCT_EXT_LOW_SPEED_CLOCK_DISABLE_CLEAR;
return dct_write_app_data(&value, DCT_EXT_LOW_SPEED_CLOCK_DISABLE_OFFSET, sizeof(value));
}
}
#endif // HAL_PLATFORM_INTERNAL_LOW_SPEED_CLOCK
}
return -1;
Expand Down
92 changes: 52 additions & 40 deletions services/inc/ncp_fw_update.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,51 +61,58 @@ namespace particle {
namespace services {

const system_tick_t NCP_FW_MODEM_POWER_ON_TIMEOUT = 60000;
const system_tick_t NCP_FW_MODEM_INSTALL_ATOK_INTERVAL = 10000;
const system_tick_t NCP_FW_MODEM_INSTALL_START_TIMEOUT = 5 * 60000;
const system_tick_t NCP_FW_MODEM_INSTALL_FINISH_TIMEOUT = 30 * 60000;
const system_tick_t NCP_FW_MODEM_CLOUD_CONNECT_TIMEOUT = 5 * 60000;
const uint32_t NCP_FW_UBLOX_R510_ENG_VERSION = 100000000;
const system_tick_t NCP_FW_MODEM_CLOUD_DISCONNECT_TIMEOUT = 1 * 60000;
const system_tick_t NCP_FW_MODEM_CELLULAR_CONNECT_TIMEOUT = 10 * 60000;
const int NCP_FW_UBLOX_DEFAULT_CID = 1;
const int NCP_FW_UUFWINSTALL_COMPLETE = 128;

enum NcpFwUpdateState {
FW_UPDATE_IDLE_STATE = 0,
FW_UPDATE_QUALIFY_FLAGS_STATE = 1,
FW_UPDATE_QUALIFY_MODEM_ON_STATE = 2,
FW_UPDATE_QUALIFY_RETRY_STATE = 3,
FW_UPDATE_SETUP_CLOUD_CONNECT_STATE = 4,
FW_UPDATE_SETUP_CLOUD_CONNECTING_STATE = 5,
FW_UPDATE_SETUP_CLOUD_CONNECTED_STATE = 6,
FW_UPDATE_DOWNLOAD_CLOUD_DISCONNECT_STATE = 7,
FW_UPDATE_DOWNLOAD_CELL_DISCONNECTING_STATE = 8,
FW_UPDATE_DOWNLOAD_CELL_CONNECTING_STATE = 9,
FW_UPDATE_DOWNLOAD_HTTPS_SETUP_STATE = 10,
FW_UPDATE_DOWNLOAD_READY_STATE = 11,
FW_UPDATE_INSTALL_CELL_DISCONNECTING_STATE = 12,
FW_UPDATE_INSTALL_CELL_DISCONNECTED_STATE = 13,
FW_UPDATE_INSTALL_STATE_STARTING = 14,
FW_UPDATE_INSTALL_STATE_WAITING = 15,
FW_UPDATE_FINISHED_POWER_OFF_STATE = 16,
FW_UPDATE_FINISHED_POWERING_OFF_STATE = 17,
FW_UPDATE_FINISHED_CLOUD_CONNECTING_STATE = 18,
FW_UPDATE_FINISHED_CLOUD_CONNECTED_STATE = 19,
FW_UPDATE_FINISHED_IDLE_STATE = 20,
FW_UPDATE_SETUP_CLOUD_CONNECT_STATE = 2,
FW_UPDATE_SETUP_CLOUD_CONNECTING_STATE = 3,
FW_UPDATE_SETUP_CLOUD_CONNECTED_STATE = 4,
FW_UPDATE_DOWNLOAD_CLOUD_DISCONNECT_STATE = 5,
FW_UPDATE_DOWNLOAD_CELL_DISCONNECTING_STATE = 6,
FW_UPDATE_DOWNLOAD_CELL_CONNECTING_STATE = 7,
FW_UPDATE_DOWNLOAD_HTTPS_SETUP_STATE = 8,
FW_UPDATE_DOWNLOAD_READY_STATE = 9,
FW_UPDATE_INSTALL_CELL_DISCONNECTING_STATE = 10,
FW_UPDATE_INSTALL_STATE_STARTING = 11,
FW_UPDATE_INSTALL_STATE_WAITING = 12,
FW_UPDATE_FINISHED_POWER_OFF_STATE = 13,
FW_UPDATE_FINISHED_POWERING_OFF_STATE = 14,
FW_UPDATE_FINISHED_CLOUD_CONNECTING_STATE = 15,
FW_UPDATE_FINISHED_CLOUD_CONNECTED_STATE = 16,
FW_UPDATE_FINISHED_IDLE_STATE = 17,
};

enum NcpFwUpdateStatus {
FW_UPDATE_IDLE_STATUS = 0,
FW_UPDATE_DOWNLOADING_STATUS = 1,
FW_UPDATE_UPDATING_STATUS = 2,
FW_UPDATE_SUCCESS_STATUS = 3,
FW_UPDATE_NONE_STATUS = -1, // for diagnostics
FW_UPDATE_FAILED_STATUS = -2,
FW_UPDATE_FAILED_DOWNLOAD_RETRY_MAX_STATUS = -3,
FW_UPDATE_FAILED_START_INSTALL_TIMEOUT_STATUS = -4,
FW_UPDATE_FAILED_INSTALL_AT_ERROR_STATUS = -5,
FW_UPDATE_FAILED_SAME_VERSION_STATUS = -6,
FW_UPDATE_FAILED_INSTALL_TIMEOUT_STATUS = -7,
FW_UPDATE_FAILED_POWER_OFF_TIMEOUT_STATUS = -8,
FW_UPDATE_FAILED_CLOUD_CONNECT_TIMEOUT_STATUS = -9,
FW_UPDATE_FAILED_PUBLISH_RESULT_STATUS = -10,
FW_UPDATE_IDLE_STATUS = 0,
FW_UPDATE_DOWNLOADING_STATUS = 1,
FW_UPDATE_UPDATING_STATUS = 2,
FW_UPDATE_SUCCESS_STATUS = 3,
FW_UPDATE_NONE_STATUS = -1, // for diagnostics
FW_UPDATE_FAILED_STATUS = -2,
FW_UPDATE_FAILED_QUALIFY_FLAGS_STATUS = -3,
FW_UPDATE_FAILED_CLOUD_CONNECT_ON_ENTRY_TIMEOUT_STATUS = -4,
FW_UPDATE_FAILED_PUBLISH_START_STATUS = -5,
FW_UPDATE_FAILED_SETUP_CELLULAR_DISCONNECT_TIMEOUT_STATUS = -6,
FW_UPDATE_FAILED_CELLULAR_CONNECT_TIMEOUT_STATUS = -7,
FW_UPDATE_FAILED_HTTPS_SETUP_STATUS = -8,
FW_UPDATE_FAILED_DOWNLOAD_RETRY_MAX_STATUS = -9,
FW_UPDATE_FAILED_INSTALL_CELLULAR_DISCONNECT_TIMEOUT_STATUS = -10,
FW_UPDATE_FAILED_START_INSTALL_TIMEOUT_STATUS = -11,
FW_UPDATE_FAILED_INSTALL_AT_ERROR_STATUS = -12,
FW_UPDATE_FAILED_SAME_VERSION_STATUS = -13,
FW_UPDATE_FAILED_INSTALL_TIMEOUT_STATUS = -14,
FW_UPDATE_FAILED_POWER_OFF_TIMEOUT_STATUS = -15,
FW_UPDATE_FAILED_CLOUD_CONNECT_ON_EXIT_TIMEOUT_STATUS = -16,
FW_UPDATE_FAILED_PUBLISH_RESULT_STATUS = -17,
};

struct HTTPSresponse {
Expand All @@ -126,12 +133,13 @@ struct NcpFwUpdateData {
int firmwareVersion; // 0;
int startingFirmwareVersion; // 0;
int updateVersion; // 0;
uint8_t updateAvailable; // SYSTEM_NCP_FW_UPDATE_STATUS_UNKNOWN;
uint8_t isUserConfig; // 0;
NcpFwUpdateConfig userConfigData; // 0;
uint32_t footer; // NCP_FW_DATA_FOOTER;
};

/**
/**
* struct NcpFwUpdateConfig {
* const uint32_t start_version;
* const uint32_t end_version;
Expand All @@ -155,28 +163,31 @@ class NcpFwUpdate {
*/
static NcpFwUpdate* instance();

NcpFwUpdate();
~NcpFwUpdate();

int checkUpdate(const NcpFwUpdateConfig* userConfigData);
void init(NcpFwUpdateCallbacks* callbacks);
int process();
int getStatusDiagnostics();
int setConfig(const NcpFwUpdateConfig* userConfigData = nullptr);
int checkUpdate(uint32_t version = 0);
int enableUpdates();
int updateStatus();

private:
NcpFwUpdate();
~NcpFwUpdate();

NcpFwUpdateState ncpFwUpdateState_;
NcpFwUpdateStatus ncpFwUpdateStatus_;
NcpFwUpdateStatus ncpFwUpdateStatusDiagnostics_;
int foatReady_;
system_tick_t startInstallTimer_;
system_tick_t startTimer_;
system_tick_t atOkCheckTimer_;
int lastRespCode_;
int atResp_;
int atResponsive_;
int startingFirmwareVersion_;
int firmwareVersion_;
int updateVersion_;
int updateAvailable_;
bool isUserConfig_;
system_tick_t cooldownTimer_;
system_tick_t cooldownTimeout_;
Expand All @@ -198,6 +209,7 @@ class NcpFwUpdate {
static int cbUPSND_(int type, const char* buf, int len, int* data);
static int cbCOPS_(int type, const char* buf, int len, int* data);
static int httpRespCallback_(AtResponseReader* reader, const char* prefix, void* data);
static int cgevCallback_(AtResponseReader* reader, const char* prefix, void* data);
uint32_t getAppFirmwareVersion_();
int setupHTTPSProperties_();
void cooldown_(system_tick_t timer);
Expand Down
2 changes: 1 addition & 1 deletion services/inc/ncp_fw_update_dynalib.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extern "C" {
#endif

#if !defined(PARTICLE_USER_MODULE) || defined(PARTICLE_USE_UNSTABLE_API)
int ncp_fw_udpate_check(const NcpFwUpdateConfig* data, void* reserved);
int ncp_fw_udpate_config(const NcpFwUpdateConfig* data, void* reserved);
#endif // !defined(PARTICLE_USER_MODULE) || defined(PARTICLE_USE_UNSTABLE_API)

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion services/inc/services_dynalib.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ DYNALIB_FN(BASE_IDX + 0, services, set_system_error_message, void(const char*, .
DYNALIB_FN(BASE_IDX + 1, services, clear_system_error_message, void())
DYNALIB_FN(BASE_IDX + 2, services, get_system_error_message, const char*(int))
DYNALIB_FN(BASE_IDX + 3, services, jsmn_parse, int(jsmn_parser*, const char*, size_t, jsmntok_t*, unsigned int, void*))
DYNALIB_FN(BASE_IDX + 4, services, ncp_fw_udpate_check, int(const NcpFwUpdateConfig*, void*))
DYNALIB_FN(BASE_IDX + 4, services, ncp_fw_udpate_config, int(const NcpFwUpdateConfig*, void*))

DYNALIB_END(services)

Expand Down
22 changes: 22 additions & 0 deletions services/inc/system_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,28 @@ typedef enum system_flag_t {

} system_flag_t;

/**
* NCP Firmware Update Available Status for Cellular Wiring API Cellular.updateStatus()
*/
typedef enum {
/**
* The system will check locally for firmware updates when the modem is initialized.
*/
SYSTEM_NCP_FW_UPDATE_STATUS_UNKNOWN = 0,
/**
* No firmware update available.
*/
SYSTEM_NCP_FW_UPDATE_STATUS_NOT_AVAILABLE = 1,
/**
* A firmware update is available.
*/
SYSTEM_NCP_FW_UPDATE_STATUS_PENDING = 2,
/**
* A firmware update is in progress.
*/
SYSTEM_NCP_FW_UPDATE_STATUS_IN_PROGRESS = 3
} NcpFwUpdateAvailableStatus;

#ifdef __cplusplus

#include "enumflags.h"
Expand Down
Loading

0 comments on commit 0e2f5db

Please sign in to comment.