2017-07-07 20:04:03 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017 Linaro Limited
|
2019-01-25 23:13:07 +01:00
|
|
|
* Copyright (c) 2018-2019 Foundries.io
|
2017-07-07 20:04:03 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2018-09-19 10:22:19 +02:00
|
|
|
#define LOG_MODULE_NAME net_lwm2m_obj_firmware
|
|
|
|
#define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
|
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/logging/log.h>
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
#include <string.h>
|
2021-06-15 15:05:56 +02:00
|
|
|
#include <stdio.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/init.h>
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
#include "lwm2m_object.h"
|
|
|
|
#include "lwm2m_engine.h"
|
|
|
|
|
2021-02-02 13:14:21 +01:00
|
|
|
#define FIRMWARE_VERSION_MAJOR 1
|
|
|
|
#define FIRMWARE_VERSION_MINOR 0
|
|
|
|
|
2022-09-19 14:11:56 +02:00
|
|
|
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT_MULTIPLE)
|
|
|
|
#define MAX_INSTANCE_COUNT CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_INSTANCE_COUNT
|
2021-06-15 15:05:56 +02:00
|
|
|
#else
|
|
|
|
#define MAX_INSTANCE_COUNT 1
|
|
|
|
#endif
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
/* Firmware resource IDs */
|
|
|
|
#define FIRMWARE_PACKAGE_ID 0
|
2017-10-11 20:39:37 +02:00
|
|
|
#define FIRMWARE_PACKAGE_URI_ID 1
|
2017-07-07 20:04:03 +02:00
|
|
|
#define FIRMWARE_UPDATE_ID 2
|
|
|
|
#define FIRMWARE_STATE_ID 3
|
|
|
|
#define FIRMWARE_UPDATE_RESULT_ID 5
|
2018-05-01 02:27:28 +02:00
|
|
|
#define FIRMWARE_PACKAGE_NAME_ID 6
|
|
|
|
#define FIRMWARE_PACKAGE_VERSION_ID 7
|
2021-07-19 09:49:37 +02:00
|
|
|
#define FIRMWARE_UPDATE_PROTO_SUPPORT_ID 8
|
2017-07-07 20:04:03 +02:00
|
|
|
#define FIRMWARE_UPDATE_DELIV_METHOD_ID 9
|
|
|
|
|
|
|
|
#define FIRMWARE_MAX_ID 10
|
|
|
|
|
|
|
|
#define DELIVERY_METHOD_PULL_ONLY 0
|
|
|
|
#define DELIVERY_METHOD_PUSH_ONLY 1
|
|
|
|
#define DELIVERY_METHOD_BOTH 2
|
|
|
|
|
|
|
|
#define PACKAGE_URI_LEN 255
|
|
|
|
|
2019-07-29 19:09:00 +02:00
|
|
|
/*
|
|
|
|
* Calculate resource instances as follows:
|
|
|
|
* start with FIRMWARE_MAX_ID
|
|
|
|
* subtract EXEC resources (1)
|
|
|
|
*/
|
|
|
|
#define RESOURCE_INSTANCE_COUNT (FIRMWARE_MAX_ID - 1)
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
/* resource state variables */
|
2021-06-15 15:05:56 +02:00
|
|
|
static uint8_t update_state[MAX_INSTANCE_COUNT];
|
|
|
|
static uint8_t update_result[MAX_INSTANCE_COUNT];
|
|
|
|
static uint8_t delivery_method[MAX_INSTANCE_COUNT];
|
|
|
|
static char package_uri[MAX_INSTANCE_COUNT][PACKAGE_URI_LEN];
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-06-15 15:05:56 +02:00
|
|
|
/* A varying number of firmware object exists */
|
2017-07-07 20:04:03 +02:00
|
|
|
static struct lwm2m_engine_obj firmware;
|
|
|
|
static struct lwm2m_engine_obj_field fields[] = {
|
2019-07-29 19:06:00 +02:00
|
|
|
OBJ_FIELD_DATA(FIRMWARE_PACKAGE_ID, W, OPAQUE),
|
|
|
|
OBJ_FIELD_DATA(FIRMWARE_PACKAGE_URI_ID, RW, STRING),
|
2017-07-07 20:04:03 +02:00
|
|
|
OBJ_FIELD_EXECUTE(FIRMWARE_UPDATE_ID),
|
|
|
|
OBJ_FIELD_DATA(FIRMWARE_STATE_ID, R, U8),
|
|
|
|
OBJ_FIELD_DATA(FIRMWARE_UPDATE_RESULT_ID, R, U8),
|
2018-05-01 02:27:28 +02:00
|
|
|
OBJ_FIELD_DATA(FIRMWARE_PACKAGE_NAME_ID, R_OPT, STRING),
|
|
|
|
OBJ_FIELD_DATA(FIRMWARE_PACKAGE_VERSION_ID, R_OPT, STRING),
|
2019-07-29 19:06:00 +02:00
|
|
|
OBJ_FIELD_DATA(FIRMWARE_UPDATE_PROTO_SUPPORT_ID, R_OPT, U8),
|
2017-07-07 20:04:03 +02:00
|
|
|
OBJ_FIELD_DATA(FIRMWARE_UPDATE_DELIV_METHOD_ID, R, U8)
|
|
|
|
};
|
|
|
|
|
2021-06-15 15:05:56 +02:00
|
|
|
static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT];
|
|
|
|
static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][FIRMWARE_MAX_ID];
|
|
|
|
static struct lwm2m_engine_res_inst res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT];
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2022-01-04 13:25:32 +01:00
|
|
|
static lwm2m_engine_set_data_cb_t write_cb[MAX_INSTANCE_COUNT];
|
|
|
|
static lwm2m_engine_execute_cb_t update_cb[MAX_INSTANCE_COUNT];
|
2023-03-04 09:38:41 +01:00
|
|
|
static lwm2m_engine_user_cb_t cancel_cb[MAX_INSTANCE_COUNT];
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
#ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
|
2021-06-15 15:05:56 +02:00
|
|
|
extern int lwm2m_firmware_start_transfer(uint16_t obj_inst_id, char *package_uri);
|
2017-07-07 20:04:03 +02:00
|
|
|
#endif
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
uint8_t lwm2m_firmware_get_update_state_inst(uint16_t obj_inst_id)
|
2017-07-05 17:07:41 +02:00
|
|
|
{
|
2021-06-15 15:05:56 +02:00
|
|
|
return update_state[obj_inst_id];
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
uint8_t lwm2m_firmware_get_update_state(void)
|
|
|
|
{
|
|
|
|
return lwm2m_firmware_get_update_state_inst(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lwm2m_firmware_set_update_state_inst(uint16_t obj_inst_id, uint8_t state)
|
2017-07-05 17:07:41 +02:00
|
|
|
{
|
|
|
|
bool error = false;
|
2023-01-05 10:35:39 +01:00
|
|
|
struct lwm2m_obj_path path = LWM2M_OBJ(LWM2M_OBJECT_FIRMWARE_ID, obj_inst_id,
|
|
|
|
FIRMWARE_UPDATE_RESULT_ID);
|
2022-08-24 11:19:18 +02:00
|
|
|
|
2023-08-14 11:55:08 +02:00
|
|
|
lwm2m_registry_lock();
|
2017-07-05 17:07:41 +02:00
|
|
|
/* Check LWM2M SPEC appendix E.6.1 */
|
|
|
|
switch (state) {
|
|
|
|
case STATE_DOWNLOADING:
|
2022-08-24 11:19:18 +02:00
|
|
|
if (update_state[obj_inst_id] == STATE_IDLE) {
|
2023-01-05 10:35:39 +01:00
|
|
|
lwm2m_set_u8(&path, RESULT_DEFAULT);
|
2022-08-24 11:19:18 +02:00
|
|
|
} else {
|
2017-07-05 17:07:41 +02:00
|
|
|
error = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_DOWNLOADED:
|
2022-08-24 11:19:18 +02:00
|
|
|
if (update_state[obj_inst_id] == STATE_DOWNLOADING) {
|
2023-01-05 10:35:39 +01:00
|
|
|
lwm2m_set_u8(&path, RESULT_DEFAULT);
|
2022-08-24 11:19:18 +02:00
|
|
|
} else if (update_state[obj_inst_id] == STATE_UPDATING) {
|
2023-01-05 10:35:39 +01:00
|
|
|
lwm2m_set_u8(&path, RESULT_UPDATE_FAILED);
|
2022-08-24 11:19:18 +02:00
|
|
|
} else {
|
2017-07-05 17:07:41 +02:00
|
|
|
error = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_UPDATING:
|
2021-06-15 15:05:56 +02:00
|
|
|
if (update_state[obj_inst_id] != STATE_DOWNLOADED) {
|
2017-07-05 17:07:41 +02:00
|
|
|
error = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_IDLE:
|
|
|
|
break;
|
|
|
|
default:
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_ERR("Unhandled state: %u", state);
|
2023-08-14 11:55:08 +02:00
|
|
|
lwm2m_registry_unlock();
|
2017-07-05 17:07:41 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error) {
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_ERR("Invalid state transition: %u -> %u",
|
2021-06-15 15:05:56 +02:00
|
|
|
update_state[obj_inst_id], state);
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2023-01-05 10:35:39 +01:00
|
|
|
path.res_id = FIRMWARE_STATE_ID;
|
2021-06-15 15:05:56 +02:00
|
|
|
|
2023-01-05 10:35:39 +01:00
|
|
|
lwm2m_set_u8(&path, state);
|
2023-08-14 11:55:08 +02:00
|
|
|
lwm2m_registry_unlock();
|
2022-01-05 12:03:19 +01:00
|
|
|
|
|
|
|
LOG_DBG("Update state = %d", state);
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
void lwm2m_firmware_set_update_state(uint8_t state)
|
|
|
|
{
|
|
|
|
lwm2m_firmware_set_update_state_inst(0, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t lwm2m_firmware_get_update_result_inst(uint16_t obj_inst_id)
|
2017-07-05 17:07:41 +02:00
|
|
|
{
|
2021-06-15 15:05:56 +02:00
|
|
|
return update_result[obj_inst_id];
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
uint8_t lwm2m_firmware_get_update_result(void)
|
|
|
|
{
|
|
|
|
return lwm2m_firmware_get_update_result_inst(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lwm2m_firmware_set_update_result_inst(uint16_t obj_inst_id, uint8_t result)
|
2017-07-05 17:07:41 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t state;
|
2017-07-05 17:07:41 +02:00
|
|
|
bool error = false;
|
2023-01-05 10:35:39 +01:00
|
|
|
struct lwm2m_obj_path path = LWM2M_OBJ(LWM2M_OBJECT_FIRMWARE_ID, obj_inst_id,
|
|
|
|
FIRMWARE_UPDATE_RESULT_ID);
|
2017-07-05 17:07:41 +02:00
|
|
|
|
2023-08-14 11:55:08 +02:00
|
|
|
lwm2m_registry_lock();
|
2017-07-05 17:07:41 +02:00
|
|
|
/* Check LWM2M SPEC appendix E.6.1 */
|
|
|
|
switch (result) {
|
|
|
|
case RESULT_DEFAULT:
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE);
|
2017-07-05 17:07:41 +02:00
|
|
|
break;
|
|
|
|
case RESULT_SUCCESS:
|
2021-06-15 15:05:56 +02:00
|
|
|
if (update_state[obj_inst_id] != STATE_UPDATING) {
|
2017-07-05 17:07:41 +02:00
|
|
|
error = true;
|
2021-06-15 15:05:56 +02:00
|
|
|
state = update_state[obj_inst_id];
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE);
|
2017-07-05 17:07:41 +02:00
|
|
|
break;
|
|
|
|
case RESULT_NO_STORAGE:
|
|
|
|
case RESULT_OUT_OF_MEM:
|
|
|
|
case RESULT_CONNECTION_LOST:
|
|
|
|
case RESULT_UNSUP_FW:
|
|
|
|
case RESULT_INVALID_URI:
|
|
|
|
case RESULT_UNSUP_PROTO:
|
2021-06-15 15:05:56 +02:00
|
|
|
if (update_state[obj_inst_id] != STATE_DOWNLOADING) {
|
2017-07-05 17:07:41 +02:00
|
|
|
error = true;
|
2021-06-15 15:05:56 +02:00
|
|
|
state = update_state[obj_inst_id];
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE);
|
2017-07-05 17:07:41 +02:00
|
|
|
break;
|
|
|
|
case RESULT_INTEGRITY_FAILED:
|
2021-06-15 15:05:56 +02:00
|
|
|
if (update_state[obj_inst_id] != STATE_DOWNLOADING &&
|
|
|
|
update_state[obj_inst_id] != STATE_UPDATING) {
|
2017-07-05 17:07:41 +02:00
|
|
|
error = true;
|
2021-06-15 15:05:56 +02:00
|
|
|
state = update_state[obj_inst_id];
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE);
|
2017-07-05 17:07:41 +02:00
|
|
|
break;
|
|
|
|
case RESULT_UPDATE_FAILED:
|
2021-06-15 15:05:56 +02:00
|
|
|
if (update_state[obj_inst_id] != STATE_DOWNLOADING &&
|
|
|
|
update_state[obj_inst_id] != STATE_UPDATING) {
|
2017-07-05 17:07:41 +02:00
|
|
|
error = true;
|
2021-06-15 15:05:56 +02:00
|
|
|
state = update_state[obj_inst_id];
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE);
|
2017-07-05 17:07:41 +02:00
|
|
|
break;
|
|
|
|
default:
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_ERR("Unhandled result: %u", result);
|
2023-08-14 11:55:08 +02:00
|
|
|
lwm2m_registry_unlock();
|
2017-07-05 17:07:41 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error) {
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_ERR("Unexpected result(%u) set while state is %u",
|
|
|
|
result, state);
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2023-01-05 10:35:39 +01:00
|
|
|
lwm2m_set_u8(&path, result);
|
2023-08-14 11:55:08 +02:00
|
|
|
lwm2m_registry_unlock();
|
2022-01-05 12:03:19 +01:00
|
|
|
LOG_DBG("Update result = %d", result);
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
void lwm2m_firmware_set_update_result(uint8_t result)
|
|
|
|
{
|
|
|
|
lwm2m_firmware_set_update_result_inst(0, result);
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id,
|
|
|
|
uint16_t res_inst_id, uint8_t *data, uint16_t data_len,
|
2017-07-07 20:04:03 +02:00
|
|
|
bool last_block, size_t total_size)
|
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t state;
|
2022-01-04 13:25:32 +01:00
|
|
|
int ret = 0;
|
2023-03-04 09:38:41 +01:00
|
|
|
lwm2m_engine_set_data_cb_t write_callback;
|
|
|
|
lwm2m_engine_user_cb_t cancel_callback;
|
2017-07-25 10:54:25 +02:00
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
state = lwm2m_firmware_get_update_state_inst(obj_inst_id);
|
2017-07-25 10:54:25 +02:00
|
|
|
if (state == STATE_IDLE) {
|
|
|
|
/* TODO: setup timer to check download status,
|
|
|
|
* make sure it fail after timeout
|
|
|
|
*/
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_DOWNLOADING);
|
2022-05-22 12:48:31 +02:00
|
|
|
} else if (state == STATE_DOWNLOADED) {
|
|
|
|
if (data_len == 0U || (data_len == 1U && data[0] == '\0')) {
|
2017-07-25 10:54:25 +02:00
|
|
|
/* reset to state idle and result default */
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_DEFAULT);
|
2023-03-04 09:38:41 +01:00
|
|
|
cancel_callback = lwm2m_firmware_get_cancel_cb_inst(obj_inst_id);
|
|
|
|
if (cancel_callback) {
|
|
|
|
ret = cancel_callback(obj_inst_id);
|
|
|
|
}
|
2022-05-22 12:48:31 +02:00
|
|
|
LOG_DBG("Update canceled by writing %d bytes", data_len);
|
2017-10-27 23:57:44 +02:00
|
|
|
return 0;
|
2017-07-25 10:54:25 +02:00
|
|
|
}
|
2022-05-22 12:48:31 +02:00
|
|
|
LOG_WRN("Download has already completed");
|
|
|
|
return -EPERM;
|
|
|
|
} else if (state != STATE_DOWNLOADING) {
|
|
|
|
LOG_WRN("Cannot download: state = %d", state);
|
2017-07-25 10:54:25 +02:00
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2023-03-04 09:38:41 +01:00
|
|
|
write_callback = lwm2m_firmware_get_write_cb_inst(obj_inst_id);
|
|
|
|
if (write_callback) {
|
|
|
|
ret = write_callback(obj_inst_id, res_id, res_inst_id, data, data_len, last_block,
|
|
|
|
total_size);
|
2022-01-04 13:25:32 +01:00
|
|
|
}
|
|
|
|
|
2017-11-02 11:36:24 +01:00
|
|
|
if (ret >= 0) {
|
|
|
|
if (last_block) {
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_DOWNLOADED);
|
2017-07-25 10:54:25 +02:00
|
|
|
}
|
|
|
|
|
2017-11-02 11:36:24 +01:00
|
|
|
return 0;
|
|
|
|
} else if (ret == -ENOMEM) {
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_OUT_OF_MEM);
|
2017-11-02 11:36:24 +01:00
|
|
|
} else if (ret == -ENOSPC) {
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_NO_STORAGE);
|
2017-11-02 11:36:24 +01:00
|
|
|
/* Response 4.13 (RFC7959, section 2.9.3) */
|
|
|
|
/* TODO: should include size1 option to indicate max size */
|
|
|
|
ret = -EFBIG;
|
|
|
|
} else if (ret == -EFAULT) {
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_INTEGRITY_FAILED);
|
2021-06-15 15:05:56 +02:00
|
|
|
} else if (ret == -ENOMSG) {
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_UNSUP_FW);
|
2017-11-02 11:36:24 +01:00
|
|
|
} else {
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_UPDATE_FAILED);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2017-10-27 23:57:44 +02:00
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id,
|
|
|
|
uint16_t res_inst_id, uint8_t *data, uint16_t data_len,
|
2017-07-07 20:04:03 +02:00
|
|
|
bool last_block, size_t total_size)
|
|
|
|
{
|
2022-06-20 07:43:37 +02:00
|
|
|
LOG_DBG("PACKAGE_URI WRITE: %s", package_uri[obj_inst_id]);
|
2017-07-05 17:07:41 +02:00
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
#ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
|
2021-12-14 08:52:54 +01:00
|
|
|
uint8_t state = lwm2m_firmware_get_update_state_inst(obj_inst_id);
|
2024-03-11 16:11:47 +01:00
|
|
|
bool empty_uri = data_len == 0 || strnlen(data, data_len) == 0;
|
2017-07-05 17:07:41 +02:00
|
|
|
|
|
|
|
if (state == STATE_IDLE) {
|
2024-03-11 16:11:47 +01:00
|
|
|
if (!empty_uri) {
|
2022-09-26 10:36:57 +02:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_DOWNLOADING);
|
2021-06-15 15:05:56 +02:00
|
|
|
lwm2m_firmware_start_transfer(obj_inst_id, package_uri[obj_inst_id]);
|
2020-09-03 12:38:24 +02:00
|
|
|
}
|
2024-03-11 16:11:47 +01:00
|
|
|
} else if (state == STATE_DOWNLOADED && empty_uri) {
|
2017-07-05 17:07:41 +02:00
|
|
|
/* reset to state idle and result default */
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_DEFAULT);
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return 0;
|
2017-10-27 23:57:44 +02:00
|
|
|
#else
|
|
|
|
return -EINVAL;
|
2017-07-05 17:07:41 +02:00
|
|
|
#endif
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void lwm2m_firmware_set_write_cb(lwm2m_engine_set_data_cb_t cb)
|
|
|
|
{
|
2022-01-04 13:25:32 +01:00
|
|
|
lwm2m_firmware_set_write_cb_inst(0, cb);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void)
|
|
|
|
{
|
2022-01-04 13:25:32 +01:00
|
|
|
return lwm2m_firmware_get_write_cb_inst(0);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2020-12-10 10:17:14 +01:00
|
|
|
void lwm2m_firmware_set_update_cb(lwm2m_engine_execute_cb_t cb)
|
2017-07-05 17:07:41 +02:00
|
|
|
{
|
2022-01-04 13:25:32 +01:00
|
|
|
lwm2m_firmware_set_update_cb_inst(0, cb);
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2020-12-10 10:17:14 +01:00
|
|
|
lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb(void)
|
2017-07-05 17:07:41 +02:00
|
|
|
{
|
2022-01-04 13:25:32 +01:00
|
|
|
return lwm2m_firmware_get_update_cb_inst(0);
|
|
|
|
}
|
|
|
|
|
2023-03-04 09:38:41 +01:00
|
|
|
void lwm2m_firmware_set_cancel_cb(lwm2m_engine_user_cb_t cb)
|
|
|
|
{
|
|
|
|
lwm2m_firmware_set_cancel_cb_inst(0, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
lwm2m_engine_user_cb_t lwm2m_firmware_get_cancel_cb(void)
|
|
|
|
{
|
|
|
|
return lwm2m_firmware_get_cancel_cb_inst(0);
|
|
|
|
}
|
|
|
|
|
2022-01-04 13:25:32 +01:00
|
|
|
void lwm2m_firmware_set_write_cb_inst(uint16_t obj_inst_id, lwm2m_engine_set_data_cb_t cb)
|
|
|
|
{
|
|
|
|
write_cb[obj_inst_id] = cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb_inst(uint16_t obj_inst_id)
|
|
|
|
{
|
|
|
|
return write_cb[obj_inst_id];
|
|
|
|
}
|
|
|
|
|
|
|
|
void lwm2m_firmware_set_update_cb_inst(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
|
|
|
|
{
|
|
|
|
update_cb[obj_inst_id] = cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id)
|
|
|
|
{
|
|
|
|
return update_cb[obj_inst_id];
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2023-03-04 09:38:41 +01:00
|
|
|
void lwm2m_firmware_set_cancel_cb_inst(uint16_t obj_inst_id, lwm2m_engine_user_cb_t cb)
|
|
|
|
{
|
|
|
|
cancel_cb[obj_inst_id] = cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwm2m_engine_user_cb_t lwm2m_firmware_get_cancel_cb_inst(uint16_t obj_inst_id)
|
|
|
|
{
|
|
|
|
return cancel_cb[obj_inst_id];
|
|
|
|
}
|
|
|
|
|
2020-12-10 10:17:14 +01:00
|
|
|
static int firmware_update_cb(uint16_t obj_inst_id,
|
|
|
|
uint8_t *args, uint16_t args_len)
|
2017-07-05 17:07:41 +02:00
|
|
|
{
|
2020-12-10 10:17:14 +01:00
|
|
|
lwm2m_engine_execute_cb_t callback;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t state;
|
2017-07-05 17:07:41 +02:00
|
|
|
int ret;
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
state = lwm2m_firmware_get_update_state_inst(obj_inst_id);
|
2017-07-05 17:07:41 +02:00
|
|
|
if (state != STATE_DOWNLOADED) {
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_ERR("State other than downloaded: %d", state);
|
2017-10-11 20:39:37 +02:00
|
|
|
return -EPERM;
|
2017-07-05 17:07:41 +02:00
|
|
|
}
|
|
|
|
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_UPDATING);
|
2017-07-05 17:07:41 +02:00
|
|
|
|
2022-01-04 13:25:32 +01:00
|
|
|
callback = lwm2m_firmware_get_update_cb_inst(obj_inst_id);
|
2017-07-05 17:07:41 +02:00
|
|
|
if (callback) {
|
2020-12-10 10:17:14 +01:00
|
|
|
ret = callback(obj_inst_id, args, args_len);
|
2017-07-05 17:07:41 +02:00
|
|
|
if (ret < 0) {
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_ERR("Failed to update firmware: %d", ret);
|
2021-12-14 08:52:54 +01:00
|
|
|
lwm2m_firmware_set_update_result_inst(obj_inst_id,
|
2017-07-05 17:07:41 +02:00
|
|
|
ret == -EINVAL ? RESULT_INTEGRITY_FAILED :
|
|
|
|
RESULT_UPDATE_FAILED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static struct lwm2m_engine_obj_inst *firmware_create(uint16_t obj_inst_id)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2023-06-07 13:59:23 +02:00
|
|
|
int index, i = 0, j = 0;
|
|
|
|
|
|
|
|
/* Check that there is no other instance with this ID */
|
|
|
|
for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
|
|
|
|
if (inst[index].obj && inst[index].obj_inst_id == obj_inst_id) {
|
|
|
|
LOG_ERR("Can not create instance - "
|
|
|
|
"already existing: %u", obj_inst_id);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
|
|
|
|
if (!inst[index].obj) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index >= MAX_INSTANCE_COUNT) {
|
|
|
|
LOG_ERR("Can not create instance - "
|
|
|
|
"no more room: %u", obj_inst_id);
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-07-29 19:09:00 +02:00
|
|
|
|
2023-06-07 13:59:23 +02:00
|
|
|
init_res_instance(res_inst[index], ARRAY_SIZE(res_inst[index]));
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
/* initialize instance resource data */
|
2023-06-07 13:59:23 +02:00
|
|
|
INIT_OBJ_RES_OPT(FIRMWARE_PACKAGE_ID, res[index], i, res_inst[index], j, 1,
|
2021-06-15 15:05:56 +02:00
|
|
|
false, true, NULL, NULL, NULL, package_write_cb, NULL);
|
2023-06-07 13:59:23 +02:00
|
|
|
INIT_OBJ_RES_LEN(FIRMWARE_PACKAGE_URI_ID, res[index], i, res_inst[index], j, 1,
|
|
|
|
false, true, package_uri[index], PACKAGE_URI_LEN, 0, NULL, NULL, NULL,
|
2021-06-15 15:05:56 +02:00
|
|
|
package_uri_write_cb, NULL);
|
2023-06-07 13:59:23 +02:00
|
|
|
INIT_OBJ_RES_EXECUTE(FIRMWARE_UPDATE_ID, res[index], i, firmware_update_cb);
|
|
|
|
INIT_OBJ_RES_DATA(FIRMWARE_STATE_ID, res[index], i, res_inst[index], j,
|
|
|
|
&(update_state[index]), sizeof(update_state[index]));
|
|
|
|
INIT_OBJ_RES_DATA(FIRMWARE_UPDATE_RESULT_ID, res[index], i, res_inst[index], j,
|
|
|
|
&(update_result[index]), sizeof(update_result[index]));
|
|
|
|
INIT_OBJ_RES_OPTDATA(FIRMWARE_PACKAGE_NAME_ID, res[index], i,
|
|
|
|
res_inst[index], j);
|
|
|
|
INIT_OBJ_RES_OPTDATA(FIRMWARE_PACKAGE_VERSION_ID, res[index], i,
|
|
|
|
res_inst[index], j);
|
|
|
|
INIT_OBJ_RES_MULTI_OPTDATA(FIRMWARE_UPDATE_PROTO_SUPPORT_ID, res[index], i,
|
|
|
|
res_inst[index], j, 1, false);
|
|
|
|
INIT_OBJ_RES_DATA(FIRMWARE_UPDATE_DELIV_METHOD_ID, res[index], i,
|
|
|
|
res_inst[index], j, &(delivery_method[index]),
|
|
|
|
sizeof(delivery_method[index]));
|
|
|
|
|
|
|
|
inst[index].resources = res[index];
|
|
|
|
inst[index].resource_count = i;
|
2019-07-29 19:09:00 +02:00
|
|
|
|
2018-09-19 10:22:19 +02:00
|
|
|
LOG_DBG("Create LWM2M firmware instance: %d", obj_inst_id);
|
2023-06-07 13:59:23 +02:00
|
|
|
return &inst[index];
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
init: remove the need for a dummy device pointer in SYS_INIT functions
The init infrastructure, found in `init.h`, is currently used by:
- `SYS_INIT`: to call functions before `main`
- `DEVICE_*`: to initialize devices
They are all sorted according to an initialization level + a priority.
`SYS_INIT` calls are really orthogonal to devices, however, the required
function signature requires a `const struct device *dev` as a first
argument. The only reason for that is because the same init machinery is
used by devices, so we have something like:
```c
struct init_entry {
int (*init)(const struct device *dev);
/* only set by DEVICE_*, otherwise NULL */
const struct device *dev;
}
```
As a result, we end up with such weird/ugly pattern:
```c
static int my_init(const struct device *dev)
{
/* always NULL! add ARG_UNUSED to avoid compiler warning */
ARG_UNUSED(dev);
...
}
```
This is really a result of poor internals isolation. This patch proposes
a to make init entries more flexible so that they can accept sytem
initialization calls like this:
```c
static int my_init(void)
{
...
}
```
This is achieved using a union:
```c
union init_function {
/* for SYS_INIT, used when init_entry.dev == NULL */
int (*sys)(void);
/* for DEVICE*, used when init_entry.dev != NULL */
int (*dev)(const struct device *dev);
};
struct init_entry {
/* stores init function (either for SYS_INIT or DEVICE*)
union init_function init_fn;
/* stores device pointer for DEVICE*, NULL for SYS_INIT. Allows
* to know which union entry to call.
*/
const struct device *dev;
}
```
This solution **does not increase ROM usage**, and allows to offer clean
public APIs for both SYS_INIT and DEVICE*. Note that however, init
machinery keeps a coupling with devices.
**NOTE**: This is a breaking change! All `SYS_INIT` functions will need
to be converted to the new signature. See the script offered in the
following commit.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
init: convert SYS_INIT functions to the new signature
Conversion scripted using scripts/utils/migrate_sys_init.py.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
manifest: update projects for SYS_INIT changes
Update modules with updated SYS_INIT calls:
- hal_ti
- lvgl
- sof
- TraceRecorderSource
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
tests: devicetree: devices: adjust test
Adjust test according to the recently introduced SYS_INIT
infrastructure.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
tests: kernel: threads: adjust SYS_INIT call
Adjust to the new signature: int (*init_fn)(void);
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-10-19 09:33:44 +02:00
|
|
|
static int lwm2m_firmware_init(void)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
struct lwm2m_engine_obj_inst *obj_inst = NULL;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* Set default values */
|
|
|
|
firmware.obj_id = LWM2M_OBJECT_FIRMWARE_ID;
|
2021-02-02 13:14:21 +01:00
|
|
|
firmware.version_major = FIRMWARE_VERSION_MAJOR;
|
|
|
|
firmware.version_minor = FIRMWARE_VERSION_MINOR;
|
|
|
|
firmware.is_core = true;
|
2017-07-07 20:04:03 +02:00
|
|
|
firmware.fields = fields;
|
2018-06-14 21:27:11 +02:00
|
|
|
firmware.field_count = ARRAY_SIZE(fields);
|
2021-06-15 15:05:56 +02:00
|
|
|
firmware.max_instance_count = MAX_INSTANCE_COUNT;
|
2017-07-07 20:04:03 +02:00
|
|
|
firmware.create_cb = firmware_create;
|
|
|
|
lwm2m_register_obj(&firmware);
|
|
|
|
|
2021-06-15 15:05:56 +02:00
|
|
|
|
|
|
|
for (int idx = 0; idx < MAX_INSTANCE_COUNT; idx++) {
|
|
|
|
package_uri[idx][0] = '\0';
|
|
|
|
|
|
|
|
/* Initialize state machine */
|
|
|
|
/* TODO: should be restored from the permanent storage */
|
|
|
|
update_state[idx] = STATE_IDLE;
|
|
|
|
update_result[idx] = RESULT_DEFAULT;
|
|
|
|
#ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
|
|
|
|
delivery_method[idx] = DELIVERY_METHOD_BOTH;
|
|
|
|
#else
|
|
|
|
delivery_method[idx] = DELIVERY_METHOD_PUSH_ONLY;
|
|
|
|
#endif
|
|
|
|
ret = lwm2m_create_obj_inst(LWM2M_OBJECT_FIRMWARE_ID, idx, &obj_inst);
|
|
|
|
if (ret < 0) {
|
|
|
|
LOG_DBG("Create LWM2M instance %d error: %d", idx, ret);
|
|
|
|
break;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-19 15:14:37 +01:00
|
|
|
LWM2M_CORE_INIT(lwm2m_firmware_init);
|