Skip to content
Permalink
Browse files

net: lwm2m: rework resource instance storage / access methods

LwM2M allows for multiple instance resources such the power source
resources in the device object.  These types of resources have
always been very hard to work with, and frankly were poorly
implemented.

This led to other issues where it was very hard to have
non-sequential resource instances, and each resource of this type
needed special getter / setter methods such as:
lwm2m_device_add_pwrsrc()
lwm2m_device_set_pwrsrc_voltage_mv()

Going forward, as more LwM2M objects are implemented this just
doesn't scale well.

To fix this:
- split the resource instance data out from the resource data.
  This includes the data pointer information and resource
  instance id.
- add resource id and resource instance id to the event callback
  functions so user's can see in more detail what resources and
  resource instances are being handled.
- allow generic functions like lwm2m_engine_get_*() and
  lwm2m_engine_set_*() to access resource instance data.
- adjust object resource initialization  macros to map resource
  instances to resources at the time of object instance
  creation.
- fix up the lwm2m_client as a reflection of all of these changes.

Signed-off-by: Michael Scott <mike@foundries.io>
  • Loading branch information...
mike-scott authored and jukkar committed Jul 29, 2019
1 parent 6a2f362 commit 8817d930a83a09bcc3947b4ceec96c7c09ce25cf
@@ -117,12 +117,16 @@ struct lwm2m_ctx {
* lwm2m_engine_register_pre_write_callback()
*
* @param[in] obj_inst_id Object instance ID generating the callback.
* @param[in] res_id Resource ID generating the callback.
* @param[in] res_inst_id Resource instance ID generating the callback
* (typically 0 for non-multi instance resources).
* @param[out] data_len Length of the data buffer.
*
* @return Callback returns a pointer to the data buffer or NULL for failure.
*/
typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id,
size_t *data_len);
u16_t res_id, u16_t res_inst_id,
size_t *data_len);

/**
* @brief Asynchronous callback when data has been set to a resource buffer.
@@ -135,6 +139,9 @@ typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id,
* lwm2m_engine_register_post_write_callback()
*
* @param[in] obj_inst_id Object instance ID generating the callback.
* @param[in] res_id Resource ID generating the callback.
* @param[in] res_inst_id Resource instance ID generating the callback
* (typically 0 for non-multi instance resources).
* @param[in] data Pointer to data.
* @param[in] data_len Length of the data.
* @param[in] last_block Flag used during block transfer to indicate the last
@@ -147,8 +154,9 @@ typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id,
* reason of failure or 0 for success.
*/
typedef int (*lwm2m_engine_set_data_cb_t)(u16_t obj_inst_id,
u8_t *data, u16_t data_len,
bool last_block, size_t total_size);
u16_t res_id, u16_t res_inst_id,
u8_t *data, u16_t data_len,
bool last_block, size_t total_size);

/**
* @brief Asynchronous event notification callback.
@@ -221,7 +229,7 @@ typedef int (*lwm2m_engine_user_cb_t)(u16_t obj_inst_id);
* @return The newly added index of the power source. The index is used
* for removing the power source, setting voltage or setting current.
*/
int lwm2m_device_add_pwrsrc(u8_t pwr_src_type); /* returns index */
__deprecated int lwm2m_device_add_pwrsrc(u8_t pwr_src_type);

/**
* @brief Remove power source previously registered in the LwM2M Device object.
@@ -231,7 +239,7 @@ int lwm2m_device_add_pwrsrc(u8_t pwr_src_type); /* returns index */
*
* @return 0 for success or negative in case of error.
*/
int lwm2m_device_remove_pwrsrc(int index);
__deprecated int lwm2m_device_remove_pwrsrc(int index);

/**
* @brief Set power source voltage (in millivolts).
@@ -242,7 +250,7 @@ int lwm2m_device_remove_pwrsrc(int index);
*
* @return 0 for success or negative in case of error.
*/
int lwm2m_device_set_pwrsrc_voltage_mv(int index, int voltage_mv);
__deprecated int lwm2m_device_set_pwrsrc_voltage_mv(int index, int voltage_mv);

/**
* @brief Set power source current (in milliamps).
@@ -253,7 +261,7 @@ int lwm2m_device_set_pwrsrc_voltage_mv(int index, int voltage_mv);
*
* @return 0 for success or negative in case of error.
*/
int lwm2m_device_set_pwrsrc_current_ma(int index, int current_ma);
__deprecated int lwm2m_device_set_pwrsrc_current_ma(int index, int current_ma);

/**
* @brief Register a new error code with LwM2M Device object.
@@ -772,6 +780,30 @@ int lwm2m_engine_set_res_data(char *pathstr, void *data_ptr, u16_t data_len,
int lwm2m_engine_get_res_data(char *pathstr, void **data_ptr, u16_t *data_len,
u8_t *data_flags);

/**
* @brief Create a resource instance
*
* LwM2M clients use this function to create multi-resource instances:
* Example to create 0 instance of device available power sources:
* lwm2m_engine_create_res_inst("3/0/6/0");
*
* @param[in] pathstr LwM2M path string "obj/obj-inst/res/res-inst"
*
* @return 0 for success or negative in case of error.
*/
int lwm2m_engine_create_res_inst(char *pathstr);

/**
* @brief Delete a resource instance
*
* Use this function to remove an existing resource instance
*
* @param[in] pathstr LwM2M path string "obj/obj-inst/res/res-inst"
*
* @return 0 for success or negative in case of error.
*/
int lwm2m_engine_delete_res_inst(char *pathstr);

/**
* @brief Start the LwM2M engine
*
@@ -63,12 +63,16 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#define LED_GPIO_PORT DT_ALIAS_LED0_GPIOS_CONTROLLER
#define LED_GPIO_PIN DT_ALIAS_LED0_GPIOS_PIN

static int pwrsrc_bat;
static int pwrsrc_usb;
static int battery_voltage = 3800;
static int battery_current = 125;
static int usb_voltage = 5000;
static int usb_current = 900;
static u8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT;
static int bat_mv = 3800;
static int bat_ma = 125;
static u8_t usb_idx = LWM2M_DEVICE_PWR_SRC_TYPE_USB;
static int usb_mv = 5000;
static int usb_ma = 900;
static u8_t bat_level = 95;
static u8_t bat_status = LWM2M_DEVICE_BATTERY_STATUS_CHARGING;
static int mem_free = 15;
static int mem_total = 25;

static struct device *led_dev;
static u32_t led_state;
@@ -94,7 +98,8 @@ static u8_t firmware_buf[64];
#endif

/* TODO: Move to a pre write hook that can handle ret codes once available */
static int led_on_off_cb(u16_t obj_inst_id, u8_t *data, u16_t data_len,
static int led_on_off_cb(u16_t obj_inst_id, u16_t res_id, u16_t res_inst_id,
u8_t *data, u16_t data_len,
bool last_block, size_t total_size)
{
int ret = 0;
@@ -150,7 +155,7 @@ static int device_reboot_cb(u16_t obj_inst_id)
/* Add an error for testing */
lwm2m_device_add_err(LWM2M_DEVICE_ERROR_LOW_POWER);
/* Change the battery voltage for testing */
lwm2m_device_set_pwrsrc_voltage_mv(pwrsrc_bat, --battery_voltage);
lwm2m_engine_set_s32("3/0/7/0", (bat_mv - 1));

return 0;
}
@@ -161,7 +166,7 @@ static int device_factory_default_cb(u16_t obj_inst_id)
/* Add an error for testing */
lwm2m_device_add_err(LWM2M_DEVICE_ERROR_GPS_FAILURE);
/* Change the USB current for testing */
lwm2m_device_set_pwrsrc_current_ma(pwrsrc_usb, --usb_current);
lwm2m_engine_set_s32("3/0/8/1", (usb_ma - 1));

return 0;
}
@@ -183,7 +188,8 @@ static int firmware_update_cb(u16_t obj_inst_id)
#endif


static void *temperature_get_buf(u16_t obj_inst_id, size_t *data_len)
static void *temperature_get_buf(u16_t obj_inst_id, u16_t res_id,
u16_t res_inst_id, size_t *data_len)
{
/* Last read temperature value, will use 25.5C if no sensor available */
static struct float32_value v = { 25, 500000 };
@@ -211,13 +217,15 @@ static void *temperature_get_buf(u16_t obj_inst_id, size_t *data_len)


#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
static void *firmware_get_buf(u16_t obj_inst_id, size_t *data_len)
static void *firmware_get_buf(u16_t obj_inst_id, u16_t res_id,
u16_t res_inst_id, size_t *data_len)
{
*data_len = sizeof(firmware_buf);
return firmware_buf;
}

static int firmware_block_received_cb(u16_t obj_inst_id,
u16_t res_id, u16_t res_inst_id,
u8_t *data, u16_t data_len,
bool last_block, size_t total_size)
{
@@ -228,6 +236,7 @@ static int firmware_block_received_cb(u16_t obj_inst_id,
#endif

static int timer_digital_state_cb(u16_t obj_inst_id,
u16_t res_id, u16_t res_inst_id,
u8_t *data, u16_t data_len,
bool last_block, size_t total_size)
{
@@ -291,34 +300,30 @@ static int lwm2m_setup(void)
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_register_exec_callback("3/0/4", device_reboot_cb);
lwm2m_engine_register_exec_callback("3/0/5", device_factory_default_cb);
lwm2m_engine_set_u8("3/0/9", 95); /* battery level */
lwm2m_engine_set_u32("3/0/10", 15); /* mem free */
lwm2m_engine_set_res_data("3/0/9", &bat_level, sizeof(bat_level), 0);
lwm2m_engine_set_res_data("3/0/10", &mem_free, sizeof(mem_free), 0);
lwm2m_engine_set_res_data("3/0/17", CLIENT_DEVICE_TYPE,
sizeof(CLIENT_DEVICE_TYPE),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_set_res_data("3/0/18", CLIENT_HW_VER,
sizeof(CLIENT_HW_VER),
LWM2M_RES_DATA_FLAG_RO);
lwm2m_engine_set_u8("3/0/20", LWM2M_DEVICE_BATTERY_STATUS_CHARGING);
lwm2m_engine_set_u32("3/0/21", 25); /* mem total */

pwrsrc_bat = lwm2m_device_add_pwrsrc(LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT);
if (pwrsrc_bat < 0) {
LOG_ERR("LWM2M battery power source enable error (err:%d)",
pwrsrc_bat);
return pwrsrc_bat;
}
lwm2m_device_set_pwrsrc_voltage_mv(pwrsrc_bat, battery_voltage);
lwm2m_device_set_pwrsrc_current_ma(pwrsrc_bat, battery_current);

pwrsrc_usb = lwm2m_device_add_pwrsrc(LWM2M_DEVICE_PWR_SRC_TYPE_USB);
if (pwrsrc_usb < 0) {
LOG_ERR("LWM2M usb power source enable error (err:%d)",
pwrsrc_usb);
return pwrsrc_usb;
}
lwm2m_device_set_pwrsrc_voltage_mv(pwrsrc_usb, usb_voltage);
lwm2m_device_set_pwrsrc_current_ma(pwrsrc_usb, usb_current);
lwm2m_engine_set_res_data("3/0/20", &bat_status, sizeof(bat_status), 0);
lwm2m_engine_set_res_data("3/0/21", &mem_total, sizeof(mem_total), 0);

/* add power source resource instances */
lwm2m_engine_create_res_inst("3/0/6/0");
lwm2m_engine_set_res_data("3/0/6/0", &bat_idx, sizeof(bat_idx), 0);
lwm2m_engine_create_res_inst("3/0/7/0");
lwm2m_engine_set_res_data("3/0/7/0", &bat_mv, sizeof(bat_mv), 0);
lwm2m_engine_create_res_inst("3/0/8/0");
lwm2m_engine_set_res_data("3/0/8/0", &bat_ma, sizeof(bat_ma), 0);
lwm2m_engine_create_res_inst("3/0/6/1");
lwm2m_engine_set_res_data("3/0/6/1", &usb_idx, sizeof(usb_idx), 0);
lwm2m_engine_create_res_inst("3/0/7/1");
lwm2m_engine_set_res_data("3/0/7/1", &usb_mv, sizeof(usb_mv), 0);
lwm2m_engine_create_res_inst("3/0/8/1");
lwm2m_engine_set_res_data("3/0/8/1", &usb_ma, sizeof(usb_ma), 0);

/* setup FIRMWARE object */

@@ -40,6 +40,12 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#define LIGHT_STRING_SHORT 8
#define LIGHT_STRING_LONG 64

/*
* Calculate resource instances as follows:
* start with LIGHT_MAX_ID
*/
#define RESOURCE_INSTANCE_COUNT (LIGHT_MAX_ID)

/* resource state variables */
static bool on_off_value[MAX_INSTANCE_COUNT];
static u8_t dimmer_value[MAX_INSTANCE_COUNT];
@@ -63,9 +69,12 @@ static struct lwm2m_engine_obj_field fields[] = {
};

static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT];
static struct lwm2m_engine_res_inst res[MAX_INSTANCE_COUNT][LIGHT_MAX_ID];
static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][LIGHT_MAX_ID];
static struct lwm2m_engine_res_inst
res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT];

static void *on_time_read_cb(u16_t obj_inst_id, size_t *data_len)
static void *on_time_read_cb(u16_t obj_inst_id, u16_t res_id, u16_t res_inst_id,
size_t *data_len)
{
int i;

@@ -87,6 +96,7 @@ static void *on_time_read_cb(u16_t obj_inst_id, size_t *data_len)
}

static int on_time_post_write_cb(u16_t obj_inst_id,
u16_t res_id, u16_t res_inst_id,
u8_t *data, u16_t data_len,
bool last_block, size_t total_size)
{
@@ -117,7 +127,7 @@ static int on_time_post_write_cb(u16_t obj_inst_id,

static struct lwm2m_engine_obj_inst *light_control_create(u16_t obj_inst_id)
{
int index, avail = -1, i = 0;
int index, avail = -1, i = 0, j = 0;

/* Check that there is no other instance with this ID */
for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
@@ -151,24 +161,33 @@ static struct lwm2m_engine_obj_inst *light_control_create(u16_t obj_inst_id)
colour[avail][0] = '\0';
units[avail][0] = '\0';

init_res_instance(res_inst[avail], ARRAY_SIZE(res_inst[avail]));

/* initialize instance resource data */
INIT_OBJ_RES_DATA(res[avail], i, LIGHT_ON_OFF_ID,
&on_off_value[avail], sizeof(*on_off_value));
INIT_OBJ_RES_DATA(res[avail], i, LIGHT_DIMMER_ID,
&dimmer_value[avail], sizeof(*dimmer_value));
INIT_OBJ_RES(res[avail], i, LIGHT_ON_TIME_ID, 0, &on_time_value[avail],
sizeof(*on_time_value), on_time_read_cb,
NULL, on_time_post_write_cb, NULL);
INIT_OBJ_RES_DATA(res[avail], i, LIGHT_CUMULATIVE_ACTIVE_POWER_ID,
&cumulative_active_value[avail],
sizeof(*cumulative_active_value));
INIT_OBJ_RES_DATA(res[avail], i, LIGHT_POWER_FACTOR_ID,
&power_factor_value[avail], sizeof(*power_factor_value));
INIT_OBJ_RES_DATA(res[avail], i, LIGHT_COLOUR_ID,
colour[avail], LIGHT_STRING_LONG);
INIT_OBJ_RES_DATA(res[avail], i, LIGHT_SENSOR_UNITS_ID,
units[avail], LIGHT_STRING_SHORT);
INIT_OBJ_RES_DUMMY(res[avail], i, LIGHT_APPLICATION_TYPE_ID);
INIT_OBJ_RES_DATA(LIGHT_ON_OFF_ID, res[avail], i, res_inst[avail], j,
&on_off_value[avail], sizeof(*on_off_value));
INIT_OBJ_RES_DATA(LIGHT_DIMMER_ID, res[avail], i, res_inst[avail], j,
&dimmer_value[avail], sizeof(*dimmer_value));
INIT_OBJ_RES(LIGHT_ON_TIME_ID, res[avail], i,
res_inst[avail], j, 1, true,
&on_time_value[avail], sizeof(*on_time_value),
on_time_read_cb, NULL, on_time_post_write_cb, NULL);
INIT_OBJ_RES_DATA(LIGHT_CUMULATIVE_ACTIVE_POWER_ID, res[avail], i,
res_inst[avail], j,
&cumulative_active_value[avail],
sizeof(*cumulative_active_value));
INIT_OBJ_RES_DATA(LIGHT_POWER_FACTOR_ID, res[avail], i,
res_inst[avail], j,
&power_factor_value[avail],
sizeof(*power_factor_value));
INIT_OBJ_RES_DATA(LIGHT_COLOUR_ID, res[avail], i,
res_inst[avail], j,
colour[avail], LIGHT_STRING_LONG);
INIT_OBJ_RES_DATA(LIGHT_SENSOR_UNITS_ID, res[avail], i,
res_inst[avail], j,
units[avail], LIGHT_STRING_SHORT);
INIT_OBJ_RES_OPTDATA(LIGHT_APPLICATION_TYPE_ID, res[avail], i,
res_inst[avail], j);

inst[avail].resources = res[avail];
inst[avail].resource_count = i;
@@ -182,7 +201,7 @@ static int ipso_light_control_init(struct device *dev)
{
/* Set default values */
(void)memset(inst, 0, sizeof(*inst) * MAX_INSTANCE_COUNT);
(void)memset(res, 0, sizeof(struct lwm2m_engine_res_inst) *
(void)memset(res, 0, sizeof(struct lwm2m_engine_res) *
MAX_INSTANCE_COUNT * LIGHT_MAX_ID);

light_control.obj_id = IPSO_OBJECT_LIGHT_CONTROL_ID;

0 comments on commit 8817d93

Please sign in to comment.
You can’t perform that action at this time.