zephyr/subsys/net/lib/lwm2m/ipso_temp_sensor.c
Michael Scott 8817d930a8 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>
2019-08-02 12:00:35 +03:00

234 lines
6.9 KiB
C

/*
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2018-2019 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Source material for IPSO Temperature Sensor object (3303):
* https://github.com/IPSO-Alliance/pub/blob/master/docs/IPSO-Smart-Objects.pdf
* Section: "10. IPSO Object: Temperature"
*/
#define LOG_MODULE_NAME net_ipso_temp_sensor
#define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <stdint.h>
#include <init.h>
#include "lwm2m_object.h"
#include "lwm2m_engine.h"
/* Server resource IDs */
#define TEMP_SENSOR_VALUE_ID 5700
#define TEMP_UNITS_ID 5701
#define TEMP_MIN_MEASURED_VALUE_ID 5601
#define TEMP_MAX_MEASURED_VALUE_ID 5602
#define TEMP_MIN_RANGE_VALUE_ID 5603
#define TEMP_MAX_RANGE_VALUE_ID 5604
#define TEMP_RESET_MIN_MAX_MEASURED_VALUES_ID 5605
#define TEMP_MAX_ID 7
#define MAX_INSTANCE_COUNT CONFIG_LWM2M_IPSO_TEMP_SENSOR_INSTANCE_COUNT
#define TEMP_STRING_SHORT 8
/*
* Calculate resource instances as follows:
* start with TEMP_MAX_ID
* subtract EXEC resources (1)
*/
#define RESOURCE_INSTANCE_COUNT (TEMP_MAX_ID - 1)
/* resource state variables */
static float32_value_t sensor_value[MAX_INSTANCE_COUNT];
static char units[MAX_INSTANCE_COUNT][TEMP_STRING_SHORT];
static float32_value_t min_measured_value[MAX_INSTANCE_COUNT];
static float32_value_t max_measured_value[MAX_INSTANCE_COUNT];
static float32_value_t min_range_value[MAX_INSTANCE_COUNT];
static float32_value_t max_range_value[MAX_INSTANCE_COUNT];
static struct lwm2m_engine_obj temp_sensor;
static struct lwm2m_engine_obj_field fields[] = {
OBJ_FIELD_DATA(TEMP_SENSOR_VALUE_ID, R, FLOAT32),
OBJ_FIELD_DATA(TEMP_UNITS_ID, R_OPT, STRING),
OBJ_FIELD_DATA(TEMP_MIN_MEASURED_VALUE_ID, R_OPT, FLOAT32),
OBJ_FIELD_DATA(TEMP_MAX_MEASURED_VALUE_ID, R_OPT, FLOAT32),
OBJ_FIELD_DATA(TEMP_MIN_RANGE_VALUE_ID, R_OPT, FLOAT32),
OBJ_FIELD_DATA(TEMP_MAX_RANGE_VALUE_ID, R_OPT, FLOAT32),
OBJ_FIELD_EXECUTE_OPT(TEMP_RESET_MIN_MAX_MEASURED_VALUES_ID),
};
static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT];
static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][TEMP_MAX_ID];
static struct lwm2m_engine_res_inst
res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT];
static void update_min_measured(u16_t obj_inst_id, int index)
{
min_measured_value[index].val1 = sensor_value[index].val1;
min_measured_value[index].val2 = sensor_value[index].val2;
NOTIFY_OBSERVER(IPSO_OBJECT_TEMP_SENSOR_ID, obj_inst_id,
TEMP_MIN_MEASURED_VALUE_ID);
}
static void update_max_measured(u16_t obj_inst_id, int index)
{
max_measured_value[index].val1 = sensor_value[index].val1;
max_measured_value[index].val2 = sensor_value[index].val2;
NOTIFY_OBSERVER(IPSO_OBJECT_TEMP_SENSOR_ID, obj_inst_id,
TEMP_MAX_MEASURED_VALUE_ID);
}
static int reset_min_max_measured_values_cb(u16_t obj_inst_id)
{
int i;
LOG_DBG("RESET MIN/MAX %d", obj_inst_id);
for (i = 0; i < MAX_INSTANCE_COUNT; i++) {
if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) {
update_min_measured(obj_inst_id, i);
update_max_measured(obj_inst_id, i);
return 0;
}
}
return -ENOENT;
}
static int sensor_value_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)
{
int i;
bool update_min = false;
bool update_max = false;
for (i = 0; i < MAX_INSTANCE_COUNT; i++) {
if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) {
/* update min / max */
if (sensor_value[i].val1 < min_measured_value[i].val1) {
update_min = true;
} else if (sensor_value[i].val1 ==
min_measured_value[i].val1 &&
sensor_value[i].val2 <
min_measured_value[i].val2) {
update_min = true;
}
if (sensor_value[i].val1 > max_measured_value[i].val1) {
update_max = true;
} else if (sensor_value[i].val1 ==
max_measured_value[i].val1 &&
sensor_value[i].val2 >
max_measured_value[i].val2) {
update_max = true;
}
if (update_min) {
update_min_measured(obj_inst_id, i);
}
if (update_max) {
update_max_measured(obj_inst_id, i);
}
}
}
return 0;
}
static struct lwm2m_engine_obj_inst *temp_sensor_create(u16_t obj_inst_id)
{
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;
}
/* Set default values */
sensor_value[index].val1 = 0;
sensor_value[index].val2 = 0;
units[index][0] = '\0';
min_measured_value[index].val1 = INT32_MAX;
min_measured_value[index].val2 = 0;
max_measured_value[index].val1 = -INT32_MAX;
max_measured_value[index].val2 = 0;
min_range_value[index].val1 = 0;
min_range_value[index].val2 = 0;
max_range_value[index].val1 = 0;
max_range_value[index].val2 = 0;
init_res_instance(res_inst[index], ARRAY_SIZE(res_inst[index]));
/* initialize instance resource data */
INIT_OBJ_RES(TEMP_SENSOR_VALUE_ID, res[index], i,
res_inst[index], j, 1, true,
&sensor_value[index], sizeof(*sensor_value),
NULL, NULL, sensor_value_write_cb, NULL);
INIT_OBJ_RES_DATA(TEMP_UNITS_ID, res[index], i, res_inst[index], j,
units[index], TEMP_STRING_SHORT);
INIT_OBJ_RES_DATA(TEMP_MIN_MEASURED_VALUE_ID, res[index], i,
res_inst[index], j, &min_measured_value[index],
sizeof(*min_measured_value));
INIT_OBJ_RES_DATA(TEMP_MAX_MEASURED_VALUE_ID, res[index], i,
res_inst[index], j, &max_measured_value[index],
sizeof(*max_measured_value));
INIT_OBJ_RES_DATA(TEMP_MIN_RANGE_VALUE_ID, res[index], i,
res_inst[index], j, &min_range_value[index],
sizeof(*min_range_value));
INIT_OBJ_RES_DATA(TEMP_MAX_RANGE_VALUE_ID, res[index], i,
res_inst[index], j, &max_range_value[index],
sizeof(*max_range_value));
INIT_OBJ_RES_EXECUTE(TEMP_RESET_MIN_MAX_MEASURED_VALUES_ID,
res[index], i, reset_min_max_measured_values_cb);
inst[index].resources = res[index];
inst[index].resource_count = i;
LOG_DBG("Create IPSO Temperature Sensor instance: %d", obj_inst_id);
return &inst[index];
}
static int ipso_temp_sensor_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) *
MAX_INSTANCE_COUNT * TEMP_MAX_ID);
temp_sensor.obj_id = IPSO_OBJECT_TEMP_SENSOR_ID;
temp_sensor.fields = fields;
temp_sensor.field_count = ARRAY_SIZE(fields);
temp_sensor.max_instance_count = MAX_INSTANCE_COUNT;
temp_sensor.create_cb = temp_sensor_create;
lwm2m_register_obj(&temp_sensor);
return 0;
}
SYS_INIT(ipso_temp_sensor_init, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);