Skip to content
This repository has been archived by the owner on Jul 31, 2024. It is now read-only.

Commit

Permalink
lightdb: rework golioth_lightdb_get() on top of coap_req
Browse files Browse the repository at this point in the history
This commit is phasing out direct CoAP dependency and low-level CoAP
handling requirement when using golioth_lightdb_get() API.

Add new golioth_lightdb_get_cb() callback based API, which is really just a
thin wrapper around golioth_coap_req_cb() API, but leaves user flexibility
of calling it from other golioth callback (which are all executed from
system_client thread) as well as from time-sensitive threads like system
workqueue.

Update samples/lightdb/get to new API. Provide examples for both
synchronous golioth_lightdb_get() and asynchronous (callback based)
golioth_lightdb_get_cb() API. Add LOG_INF() statements before and after
lightdb API calls, so that it makes it clear that main thread blocks on the
synchronous API, while continuing execution with the callback-based API.

Signed-off-by: Marcin Niestroj <m.niestroj@emb.dev>
  • Loading branch information
mniestroj committed Oct 7, 2022
1 parent e81408e commit 5796567
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 144 deletions.
39 changes: 30 additions & 9 deletions include/net/golioth/lightdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <stdint.h>
#include <zephyr/net/coap.h>
#include <net/golioth/req.h>

/**
* @defgroup golioth_lightdb Golioth LightDB
Expand All @@ -24,23 +25,43 @@ enum golioth_content_format;
#define GOLIOTH_LIGHTDB_STREAM_PATH(x) ".s/" x

/**
* @brief Get value from Golioth's LightDB
* @brief Get value from Golioth's LightDB (callback based)
*
* Get value from LightDB and initialize passed CoAP reply handler.
* Asynchronously request value from Golioth's LightDB and let @p cb be invoked when such value is
* retrieved or some error condtition happens.
*
* @param client Client instance
* @param path LightDB resource path
* @param format Requested format of payload
* @param reply CoAP reply handler object used for notifying about received
* value
* @param reply_cb Reply handler callback
* @warning Experimental API
*
* @param[in] client Client instance
* @param[in] path LightDB resource path
* @param[in] format Requested format of payload
* @param[in] cb Callback executed on response received, timeout or error
* @param[in] user_data User data passed to @p cb
*
* @retval 0 On success
* @retval <0 On failure
*/
int golioth_lightdb_get_cb(struct golioth_client *client, const uint8_t *path,
enum golioth_content_format format,
golioth_req_cb_t cb, void *user_data);

/**
* @brief Get value from Golioth's LightDB (synchronous, into preallocated buffer)
*
* Synchronously get value from Golioth's LightDB and store it into preallocated buffer.
*
* @param[in] client Client instance
* @param[in] path LightDB resource path
* @param[in] format Requested format of payload
* @param[in] data Buffer for received data
* @param[in,out] len Size of buffer on input, size of response on output
*
* @retval 0 On success
* @retval <0 On failure
*/
int golioth_lightdb_get(struct golioth_client *client, const uint8_t *path,
enum golioth_content_format format,
struct coap_reply *reply, coap_reply_t reply_cb);
uint8_t *data, size_t *len);

/**
* @brief Set value to Golioth's LightDB
Expand Down
111 changes: 85 additions & 26 deletions net/golioth/lightdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,108 @@

#include <net/golioth.h>

#include "coap_req.h"
#include "coap_utils.h"
#include "pathv.h"

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(lightdb, CONFIG_GOLIOTH_LOG_LEVEL);

int golioth_lightdb_get(struct golioth_client *client, const uint8_t *path,
enum golioth_content_format format,
struct coap_reply *reply, coap_reply_t reply_cb)
#define LIGHTDB_PATH ".d"

static inline int golioth_coap_req_lightdb_cb(struct golioth_client *client,
enum coap_method method,
const uint8_t *path,
enum golioth_content_format format,
const uint8_t *data, size_t data_len,
golioth_req_cb_t cb, void *user_data,
int flags)
{
struct coap_packet packet;
uint8_t buffer[GOLIOTH_COAP_MAX_NON_PAYLOAD_LEN];
int err;
return golioth_coap_req_cb(client, method, PATHV(LIGHTDB_PATH, path), format,
data, data_len,
cb, user_data,
flags);
}

if (!reply || !reply_cb) {
return -EINVAL;
}
static inline int golioth_coap_req_lightdb_sync(struct golioth_client *client,
enum coap_method method,
const uint8_t *path,
enum golioth_content_format format,
const uint8_t *data, size_t data_len,
golioth_req_cb_t cb, void *user_data,
int flags)
{
return golioth_coap_req_sync(client, method, PATHV(LIGHTDB_PATH, path), format,
data, data_len,
cb, user_data,
flags);
}

err = coap_packet_init(&packet, buffer, sizeof(buffer),
COAP_VERSION_1, COAP_TYPE_CON,
COAP_TOKEN_MAX_LEN, coap_next_token(),
COAP_METHOD_GET, coap_next_id());
if (err) {
return err;
int golioth_lightdb_get_cb(struct golioth_client *client, const uint8_t *path,
enum golioth_content_format format,
golioth_req_cb_t cb, void *user_data)
{
return golioth_coap_req_lightdb_cb(client, COAP_METHOD_GET, path, format,
NULL, 0,
cb, user_data,
0);
}

struct golioth_lightdb_get_prealloc_data {
uint8_t *data;
size_t capacity;
size_t len;
};

static int golioth_lightdb_get_prealloc_cb(struct golioth_req_rsp *rsp)
{
struct golioth_lightdb_get_prealloc_data *prealloc_data = rsp->user_data;
size_t total = rsp->total;

/*
* In case total length is not known, just take into account length of already received
* data.
*/
if (!total) {
total = rsp->off + rsp->len;
}

err = coap_packet_append_uri_path_from_stringz(&packet, path);
if (err) {
LOG_ERR("Unable add uri path to packet");
return err;
/* Make sure that preallocated buffer has enough capacity to store whole response. */
if (prealloc_data->capacity < total) {
LOG_WRN("Not enough capacity in buffer (%zu < %zu)",
prealloc_data->capacity, total);
return -ENOSPC;
}

err = coap_append_option_int(&packet, COAP_OPTION_ACCEPT,
format);
prealloc_data->len = total;

memcpy(&prealloc_data->data[rsp->off], rsp->data, rsp->len);

return 0;
}

int golioth_lightdb_get(struct golioth_client *client, const uint8_t *path,
enum golioth_content_format format,
uint8_t *data, size_t *len)
{
struct golioth_lightdb_get_prealloc_data prealloc_data = {
.data = data,
.capacity = *len,
};
int err;

err = golioth_coap_req_lightdb_sync(client, COAP_METHOD_GET, path, format,
NULL, 0,
golioth_lightdb_get_prealloc_cb,
&prealloc_data,
0);
if (err) {
LOG_ERR("Unable add content format to packet");
return err;
}

coap_reply_clear(reply);
coap_reply_init(reply, &packet);
reply->reply = reply_cb;
*len = prealloc_data.len;

return golioth_send_coap(client, &packet);
return 0;
}

int golioth_lightdb_set(struct golioth_client *client, const uint8_t *path,
Expand Down
52 changes: 25 additions & 27 deletions samples/lightdb/get/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,32 +144,28 @@ This is the output from the serial console:

.. code-block:: console
[00:00:01.080,000] <inf> golioth_system: Initializing
[00:00:01.080,000] <inf> net_config: Initializing network
[00:00:01.080,000] <inf> net_config: Waiting interface 1 (0x3ffb01d8) to be up...
[00:00:01.080,000] <inf> esp_event: WIFI_EVENT_STA_START
[00:00:01.080,000] <inf> net_config: Interface 1 (0x3ffb01d8) coming up
[00:00:01.080,000] <inf> net_config: Running dhcpv4 client...
[00:00:01.998,000] <inf> esp_event: WIFI_EVENT_STA_CONNECTED
[00:00:05.102,000] <inf> net_dhcpv4: Received: 192.168.0.180
[00:00:05.102,000] <inf> net_config: IPv4 address: 192.168.0.180
[00:00:05.102,000] <inf> net_config: Lease time: 7200 seconds
[00:00:05.102,000] <inf> net_config: Subnet: 255.255.255.0
[00:00:05.102,000] <inf> net_config: Router: 192.168.0.1
[00:00:05.102,000] <dbg> golioth_lightdb.main: Start LightDB get sample
[00:00:05.102,000] <inf> golioth_system: Starting connect
[00:00:05.102,000] <inf> golioth_system: Client connected!
[00:00:13.541,000] <dbg> golioth_lightdb.reply_callback: payload: {"counter":18}
[00:00:43.541,000] <err> golioth_system: RX client timeout!
[00:00:43.541,000] <inf> golioth_system: Reconnect request
[00:00:43.545,000] <inf> golioth_system: Starting connect
[00:00:43.545,000] <inf> golioth_system: Client connected!
[00:00:48.869,000] <dbg> golioth_lightdb.reply_callback: payload: {"counter":18}
[00:01:18.869,000] <err> golioth_system: RX client timeout!
[00:01:18.869,000] <inf> golioth_system: Reconnect request
[00:01:18.873,000] <inf> golioth_system: Starting connect
[00:01:18.873,000] <inf> golioth_system: Client connected!
[00:01:24.507,000] <dbg> golioth_lightdb.reply_callback: payload: {"counter":18}
[00:00:00.000,000] <inf> golioth_system: Initializing
[00:00:00.000,000] <inf> net_config: Initializing network
[00:00:00.000,000] <inf> net_config: IPv4 address: 192.0.2.1
[00:00:00.000,000] <dbg> golioth_lightdb: main: Start LightDB get sample
[00:00:00.000,000] <inf> golioth_system: Starting connect
[00:00:00.030,000] <inf> golioth_lightdb: Before request (async)
[00:00:00.030,000] <inf> golioth_lightdb: After request (async)
[00:00:00.030,000] <inf> golioth_system: Client connected!
[00:00:00.030,000] <inf> golioth_lightdb: Counter (async)
31 30 |10
[00:00:05.040,000] <inf> golioth_lightdb: Before request (sync)
[00:00:05.040,000] <inf> golioth_lightdb: Counter (sync)
31 30 |10
[00:00:05.040,000] <inf> golioth_lightdb: After request (sync)
[00:00:10.050,000] <inf> golioth_lightdb: Before request (async)
[00:00:10.050,000] <inf> golioth_lightdb: After request (async)
[00:00:10.050,000] <inf> golioth_lightdb: Counter (async)
31 31 |11
[00:00:15.060,000] <inf> golioth_lightdb: Before request (sync)
[00:00:15.060,000] <inf> golioth_lightdb: Counter (sync)
31 32 |12
[00:00:15.060,000] <inf> golioth_lightdb: After request (sync)
Set counter value
=====================
Expand All @@ -179,7 +175,9 @@ The value can be set with:

.. code-block:: console
goliothctl lightdb set <device-name> /counter -b "{\"counter\":34}"
goliothctl lightdb set <device-name> /counter -b 10
goliothctl lightdb set <device-name> /counter -b 11
goliothctl lightdb set <device-name> /counter -b 12
.. _Networking with QEMU: https://docs.zephyrproject.org/3.0.0/guides/networking/qemu_setup.html#networking-with-qemu
Expand Down
2 changes: 1 addition & 1 deletion samples/lightdb/get/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ CONFIG_MAIN_STACK_SIZE=4096
CONFIG_GOLIOTH=y
CONFIG_GOLIOTH_SYSTEM_CLIENT=y

CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=256
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=2048
Loading

0 comments on commit 5796567

Please sign in to comment.