From 0ed125388fc1c811e4b5dda35cbc565d83aef8b8 Mon Sep 17 00:00:00 2001 From: Justin Morton Date: Tue, 14 Mar 2023 15:52:03 -0700 Subject: [PATCH 1/3] samples: nrf_cloud_mqtt_multi_service: use new nrf_cloud_obj Use new nrf_cloud_obj struct and related encoding and decoding functions. IRIS-6060 Signed-off-by: Justin Morton --- doc/nrf/releases/release-notes-changelog.rst | 1 + .../nrf_cloud_mqtt_multi_service/README.rst | 6 +- .../src/application.c | 153 +++++++++--------- .../src/connection.c | 140 +++++++++------- .../src/connection.h | 17 +- 5 files changed, 166 insertions(+), 151 deletions(-) diff --git a/doc/nrf/releases/release-notes-changelog.rst b/doc/nrf/releases/release-notes-changelog.rst index f206a38fd38b..ed7e61041da6 100644 --- a/doc/nrf/releases/release-notes-changelog.rst +++ b/doc/nrf/releases/release-notes-changelog.rst @@ -211,6 +211,7 @@ nRF9160 samples * Added documentation for using the :ref:`lib_nrf_cloud_alert` and :ref:`lib_nrf_cloud_log` libraries. * Changed the :file:`overlay_nrfcloud_logging.conf` file to enable JSON logs by default. + * The :c:struct:`nrf_cloud_obj` structure and associated functions are now used to encode and decode nRF Cloud data. * :ref:`http_application_update_sample` sample: diff --git a/samples/nrf9160/nrf_cloud_mqtt_multi_service/README.rst b/samples/nrf9160/nrf_cloud_mqtt_multi_service/README.rst index 39c0b7cd83a5..032c26514a0f 100644 --- a/samples/nrf9160/nrf_cloud_mqtt_multi_service/README.rst +++ b/samples/nrf9160/nrf_cloud_mqtt_multi_service/README.rst @@ -38,7 +38,7 @@ This sample implements or demonstrates the following features: * Periodic cellular, Wi-Fi, and GNSS location tracking using the :ref:`lib_location` library. * Periodic temperature sensor sampling on your `Nordic Thingy:91`_, or fake temperature measurements on your `Nordic nRF9160 DK`_. * Transmission of sensor and GNSS location samples to the nRF Cloud portal as `nRF Cloud device messages `_. -* Construction of valid `nRF Cloud device messages `_ using `cJSON`_. +* Construction of valid `nRF Cloud device messages `_. * Minimal LED status indication using the `Zephyr LED API`_. * Transmission of an alert on sample startup using the :ref:`lib_nrf_cloud_alert` library. * Transmission of additional alerts, whenever a specified temperature limit is exceeded. @@ -117,7 +117,7 @@ It performs the following major tasks: * Establishes periodic position tracking (which the :ref:`lib_location` library performs). * Periodically samples temperature data (using the :file:`src/temperature.c` file). -* Constructs timestamped sensor sample and location `device messages `_ using `cJSON`_. +* Constructs timestamped sensor sample and location `device messages `_. * Sends sensor sample and location device messages to the :ref:`nrf_cloud_mqtt_multi_service_device_message_queue`. * Checks for and executes :ref:`remote modem AT command requests `. @@ -289,7 +289,7 @@ This plot is useful for tracking, visualizing, and debugging connection loss, re Device message formatting ========================= -This sample constructs JSON-based `device messages `_ using `cJSON`_. +This sample constructs JSON-based `device messages `_. While any valid JSON string can be sent as a device message, and accepted and stored by `nRF Cloud`_, there are some pre-designed message structures, known as schemas. The nRF Cloud portal knows how to interpret these schemas. diff --git a/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/application.c b/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/application.c index 04c651945cf9..a245d18bbfad 100644 --- a/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/application.c +++ b/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/application.c @@ -13,10 +13,8 @@ #include #include #include -#include #include -#include "nrf_cloud_codec_internal.h" #include "application.h" #include "temperature.h" #include "connection.h" @@ -44,46 +42,50 @@ BUILD_ASSERT(CONFIG_AT_CMD_REQUEST_RESPONSE_BUFFER_LENGTH >= AT_CMD_REQUEST_ERR_ static char at_req_resp_buf[CONFIG_AT_CMD_REQUEST_RESPONSE_BUFFER_LENGTH]; /** - * @brief Construct a device message cJSON object with automatically generated timestamp + * @brief Construct a device message object with automatically generated timestamp * - * The resultant cJSON object will be conformal to the General Message Schema described in the + * The resultant JSON object will be conformal to the General Message Schema described in the * application-protocols repo: * * https://github.com/nRFCloud/application-protocols * + * @param msg - The object to contain the message * @param appid - The appId for the device message * @param msg_type - The messageType for the device message - * @return cJSON* - the timestamped data device message object if successful, NULL otherwise. + * @return int - 0 on success, negative error code otherwise. */ -static cJSON *create_timestamped_device_message(const char *const appid, const char *const msg_type) +static int create_timestamped_device_message(struct nrf_cloud_obj *const msg, + const char *const appid, + const char *const msg_type) { - cJSON *msg_obj = NULL; + int err; int64_t timestamp; /* Acquire timestamp */ - if (date_time_now(×tamp)) { - LOG_ERR("Failed to create timestamp for data message " - "with appid %s", appid); - return NULL; + err = date_time_now(×tamp); + if (err) { + LOG_ERR("Failed to obtain current time, error %d", err); + return -ETIME; } - /* Create container object */ - msg_obj = json_create_req_obj(appid, msg_type); - if (msg_obj == NULL) { - LOG_ERR("Failed to create container object for timestamped data message " - "with appid %s and message type %s", appid, msg_type); - return NULL; + /* Create message object */ + err = nrf_cloud_obj_msg_init(msg, appid, msg_type); + if (err) { + LOG_ERR("Failed to initialize message with appid %s and msg type %s", + appid, msg_type); + return err; } - /* Add timestamp to container object */ - if (!cJSON_AddNumberToObject(msg_obj, NRF_CLOUD_MSG_TIMESTAMP_KEY, (double)timestamp)) { - LOG_ERR("Failed to add timestamp to data message with appid %s and message type %s", + /* Add timestamp to message object */ + err = nrf_cloud_obj_ts_add(msg, timestamp); + if (err) { + LOG_ERR("Failed to add timestamp to data message with appid %s and msg type %s", appid, msg_type); - cJSON_Delete(msg_obj); - return NULL; + nrf_cloud_obj_free(msg); + return err; } - return msg_obj; + return 0; } /** @@ -95,34 +97,28 @@ static cJSON *create_timestamped_device_message(const char *const appid, const c */ static int send_sensor_sample(const char *const sensor, double value) { - int ret = 0; + int ret; - /* Create a timestamped message container object for the sensor sample. */ - cJSON *msg_obj = create_timestamped_device_message( - sensor, NRF_CLOUD_JSON_MSG_TYPE_VAL_DATA - ); + NRF_CLOUD_OBJ_JSON_DEFINE(msg_obj); - if (msg_obj == NULL) { - ret = -EINVAL; - goto cleanup; + /* Create a timestamped message container object for the sensor sample. */ + ret = create_timestamped_device_message(&msg_obj, sensor, + NRF_CLOUD_JSON_MSG_TYPE_VAL_DATA); + if (ret) { + return -EINVAL; } /* Populate the container object with the sensor value. */ - if (cJSON_AddNumberToObject(msg_obj, NRF_CLOUD_JSON_DATA_KEY, value) == NULL) { - ret = -ENOMEM; + ret = nrf_cloud_obj_num_add(&msg_obj, NRF_CLOUD_JSON_DATA_KEY, value, false); + if (ret) { LOG_ERR("Failed to append value to %s sample container object ", sensor); - goto cleanup; + nrf_cloud_obj_free(&msg_obj); + return -ENOMEM; } /* Send the sensor sample container object as a device message. */ - ret = send_device_message_cJSON(msg_obj); - -cleanup: - if (msg_obj) { - cJSON_Delete(msg_obj); - } - return ret; + return send_device_message(&msg_obj); } /** @@ -150,22 +146,17 @@ static int send_gnss(const struct location_event_data * const loc_gnss) .has_heading = 0 } }; - - cJSON *msg_obj = cJSON_CreateObject(); + NRF_CLOUD_OBJ_JSON_DEFINE(msg_obj); /* Add the timestamp */ (void)date_time_now(&gnss_pvt.ts_ms); /* Encode the location data into a device message */ - ret = nrf_cloud_gnss_msg_json_encode(&gnss_pvt, msg_obj); + ret = nrf_cloud_obj_gnss_msg_create(&msg_obj, &gnss_pvt); if (ret == 0) { /* Send the location message */ - ret = send_device_message_cJSON(msg_obj); - } - - if (msg_obj) { - cJSON_Delete(msg_obj); + ret = send_device_message(&msg_obj); } return ret; @@ -207,34 +198,29 @@ static void on_location_update(const struct location_event_data * const location * * @param msg - The device message to check. */ -static void handle_at_cmd_requests(const char *const msg) +static void handle_at_cmd_requests(const struct nrf_cloud_data *const dev_msg) { - /* Attempt to parse the message as if it is JSON */ - struct cJSON *msg_obj = cJSON_Parse(msg); + char *cmd; + struct nrf_cloud_obj msg_obj; + int err = nrf_cloud_obj_input_decode(&msg_obj, dev_msg); - if (!msg_obj) { + if (err) { /* The message isn't JSON or otherwise couldn't be parsed. */ LOG_DBG("A general topic device message of length %d could not be parsed.", - msg ? strlen(msg) : 0); + dev_msg->len); return; } - /* Check that we are actually dealing with an AT command request */ - char *msg_appid = - cJSON_GetStringValue(cJSON_GetObjectItem(msg_obj, NRF_CLOUD_JSON_APPID_KEY)); - char *msg_type = - cJSON_GetStringValue(cJSON_GetObjectItem(msg_obj, NRF_CLOUD_JSON_MSG_TYPE_KEY)); - if (!msg_appid || !msg_type || - (strcmp(msg_appid, NRF_CLOUD_JSON_APPID_VAL_MODEM) != 0) || - (strcmp(msg_type, NRF_CLOUD_JSON_MSG_TYPE_VAL_CMD) != 0)) { + /* Confirm app ID and message type */ + err = nrf_cloud_obj_msg_check(&msg_obj, NRF_CLOUD_JSON_APPID_VAL_MODEM, + NRF_CLOUD_JSON_MSG_TYPE_VAL_CMD); + if (err) { goto cleanup; } - /* If it is, extract the command string */ - char *cmd = - cJSON_GetStringValue(cJSON_GetObjectItem(msg_obj, NRF_CLOUD_JSON_DATA_KEY)); - - if (!cmd) { + /* Get the command string */ + err = nrf_cloud_obj_str_get(&msg_obj, NRF_CLOUD_JSON_DATA_KEY, &cmd); + if (err) { /* Missing or invalid command value will be treated as a blank command */ cmd = ""; } @@ -249,7 +235,7 @@ static void handle_at_cmd_requests(const char *const msg) * We subtract 1 from the passed-in response buffer length to ensure that the response is * always null-terminated, even when the response is longer than the response buffer size. */ - int err = nrf_modem_at_cmd(at_req_resp_buf, sizeof(at_req_resp_buf) - 1, "%s", cmd); + err = nrf_modem_at_cmd(at_req_resp_buf, sizeof(at_req_resp_buf) - 1, "%s", cmd); LOG_DBG("Modem AT command response (%d, %d): %s", nrf_modem_at_err_type(err), nrf_modem_at_err(err), at_req_resp_buf); @@ -267,32 +253,39 @@ static void handle_at_cmd_requests(const char *const msg) LOG_ERR("%s", at_req_resp_buf); } - /* Free the old container object and create a new one to contain our response */ - cJSON_Delete(msg_obj); - msg_obj = create_timestamped_device_message( - NRF_CLOUD_JSON_APPID_VAL_MODEM, - NRF_CLOUD_JSON_MSG_TYPE_VAL_DATA - ); - - if (!msg_obj) { + /* To re-use msg_obj for the response message we must first free its memory and + * reset its state. + * The cmd string will no longer be valid after msg_obj is freed. + */ + cmd = NULL; + /* Free the object's allocated memory */ + (void)nrf_cloud_obj_free(&msg_obj); + /* Reset the object's state */ + (void)nrf_cloud_obj_reset(&msg_obj); + + err = create_timestamped_device_message(&msg_obj, NRF_CLOUD_JSON_APPID_VAL_MODEM, + NRF_CLOUD_JSON_MSG_TYPE_VAL_DATA); + if (err) { return; } /* Populate response with command result */ - if (!cJSON_AddStringToObject(msg_obj, NRF_CLOUD_JSON_DATA_KEY, at_req_resp_buf)) { + err = nrf_cloud_obj_str_add(&msg_obj, NRF_CLOUD_JSON_DATA_KEY, at_req_resp_buf, false); + if (err) { LOG_ERR("Failed to populate AT CMD response with modem response data"); goto cleanup; } /* Send the response */ - err = send_device_message_cJSON(msg_obj); - + err = send_device_message(&msg_obj); if (err) { LOG_ERR("Failed to send AT CMD request response, error: %d", err); } + return; + cleanup: - cJSON_Delete(msg_obj); + (void)nrf_cloud_obj_free(&msg_obj); } /** @brief Check whether temperature is acceptable. diff --git a/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.c b/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.c index 8d604ac0090c..d5d678293801 100644 --- a/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.c +++ b/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.c @@ -9,9 +9,9 @@ #include #include #include +#include #include #include -#include #include "connection.h" @@ -47,7 +47,10 @@ static K_EVENT_DEFINE(cloud_connection_events); static K_EVENT_DEFINE(datetime_connection_events); /* Message Queue for enqueing outgoing messages during offline periods. */ -K_MSGQ_DEFINE(device_message_queue, sizeof(char *), CONFIG_MAX_OUTGOING_MESSAGES, sizeof(char *)); +K_MSGQ_DEFINE(device_message_queue, + sizeof(struct nrf_cloud_obj *), + CONFIG_MAX_OUTGOING_MESSAGES, + sizeof(struct nrf_cloud_obj *)); /* Tracks the number of consecutive message-send failures. A total count greater than * CONFIG_MAX_CONSECUTIVE_SEND_FAILURES will trigger a connection reset and cooldown. @@ -294,11 +297,8 @@ static void cloud_event_handler(const struct nrf_cloud_evt *nrf_cloud_evt) * If you want to do complex operations in this callback without blocking * receipt of data from nRF Cloud, you should set up a work queue and pass * messages to it either here, or from inside the callback. - * - * The data passed in needs to be null-terminated, but the nrf_cloud library - * always appends a trailing 0 to nrf_cloud_evt->data.ptr, so it will be. */ - general_dev_msg_handler(nrf_cloud_evt->data.ptr); + general_dev_msg_handler(&nrf_cloud_evt->data); } break; @@ -472,16 +472,66 @@ static void update_shadow(void) LOG_ERR("Failed to update device shadow, error: %d", err); } } +static struct nrf_cloud_obj *allocate_dev_msg_for_queue(struct nrf_cloud_obj *msg_to_copy) +{ + struct nrf_cloud_obj *new_msg = k_malloc(sizeof(struct nrf_cloud_obj)); + + if (new_msg && msg_to_copy) { + *new_msg = *msg_to_copy; + } + + return new_msg; +} + +static int enqueue_device_message(struct nrf_cloud_obj *const msg_obj, const bool create_copy) +{ + if (!msg_obj) { + return -EINVAL; + } + + struct nrf_cloud_obj *q_msg = msg_obj; + + if (create_copy) { + /* Allocate a new nrf_cloud_obj structure for the message queue. + * Copy the contents of msg_obj, which contains a pointer to the + * original message data, into the new structure. + */ + q_msg = allocate_dev_msg_for_queue(msg_obj); + if (!q_msg) { + return -ENOMEM; + } + } + + /* Attempt to append data onto message queue. */ + LOG_DBG("Adding device message to queue"); + if (k_msgq_put(&device_message_queue, &q_msg, K_NO_WAIT)) { + LOG_ERR("Device message rejected, outgoing message queue is full"); + if (create_copy) { + k_free(q_msg); + } + return -ENOMEM; + } + + return 0; +} + +static void free_queued_dev_msg_message(struct nrf_cloud_obj *msg_obj) +{ + /* Free the memory pointed to by the msg_obj struct */ + nrf_cloud_obj_free(msg_obj); + /* Free the msg_obj struct itself */ + k_free(msg_obj); +} int consume_device_message(void) { - char *msg; + struct nrf_cloud_obj *queued_msg; int ret; LOG_DBG("Consuming an enqueued device message"); /* Wait until a message is available to send. */ - ret = k_msgq_get(&device_message_queue, &msg, K_FOREVER); + ret = k_msgq_get(&device_message_queue, &queued_msg, K_FOREVER); if (ret) { LOG_ERR("Failed to retrieve item from outgoing message queue, error: %d", ret); return -ret; @@ -501,20 +551,28 @@ int consume_device_message(void) LOG_DBG("Attempting to transmit enqueued device message"); struct nrf_cloud_tx_data mqtt_msg = { - .data.ptr = msg, - .data.len = strlen(msg), .qos = MQTT_QOS_1_AT_LEAST_ONCE, .topic_type = NRF_CLOUD_TOPIC_MESSAGE, + .obj = queued_msg }; + /* Send message */ ret = nrf_cloud_send(&mqtt_msg); + if (ret) { LOG_ERR("Transmission of enqueued device message failed, nrf_cloud_send " "gave error: %d. The message will be re-enqueued and tried again " "later.", ret); - /* Re-enqueue the message for later retry (creating a new copy of it in heap). */ - send_device_message(msg); + /* Re-enqueue the message for later retry. + * No need to create a copy since we already copied the + * message object struct when it was first enqueued. + */ + ret = enqueue_device_message(queued_msg, false); + if (ret) { + LOG_ERR("Could not re-enqueue message, discarding."); + free_queued_dev_msg_message(queued_msg); + } /* Increment the failure counter. */ send_failure_count += 1; @@ -530,6 +588,9 @@ int consume_device_message(void) k_sleep(K_SECONDS(CONFIG_CONSECUTIVE_SEND_FAILURE_COOLDOWN_SECONDS)); } } else { + /* Clean up the message receive from the queue */ + free_queued_dev_msg_message(queued_msg); + LOG_DBG("Enqueued device message consumed successfully"); /* Either overwrite the existing pattern with a short success pattern, or just @@ -545,57 +606,24 @@ int consume_device_message(void) send_failure_count = 0; } - /* Clean up. */ - k_free(msg); - return ret; } -int send_device_message(const char *const msg) +int send_device_message(struct nrf_cloud_obj *const msg_obj) { - /* Copy message data onto the heap (will be freed by the message consumer when done). */ - size_t len = strlen(msg) + 1; - char *msg_buf = k_malloc(len); - - if (!msg_buf) { - LOG_ERR("Could not alloc memory for new device message"); - return -ENOMEM; - } - strncpy(msg_buf, msg, len); - LOG_DBG("Enqueued message: %s", msg_buf); + /* Enqueue the message, creating a copy to be managed by the queue. */ + int ret = enqueue_device_message(msg_obj, true); - /* Attempt to append data onto message queue. */ - if (k_msgq_put(&device_message_queue, &msg_buf, K_NO_WAIT)) { - LOG_ERR("Device message rejected, outgoing message queue is full"); - k_free(msg_buf); - return -ENOMEM; - } - - return 0; -} - -int send_device_message_cJSON(cJSON *msg_obj) -{ - int ret = 0; - char *msg = NULL; - - if (!msg_obj) { - LOG_ERR("Cannot send NULL device message object"); - return -EINVAL; - } - - /* Convert message object to a string. */ - msg = cJSON_PrintUnformatted(msg_obj); - if (msg == NULL) { - LOG_ERR("Failed to convert cJSON device message object to string"); - return -ENOMEM; + if (ret) { + LOG_ERR("Cannot add message to queue"); + nrf_cloud_obj_free(msg_obj); + } else { + /* The message data now belongs to the queue. + * Reset the provided object so it cannot be modified. + */ + nrf_cloud_obj_reset(msg_obj); } - /* Send the string as a device message. */ - ret = send_device_message(msg); - - /* Clean up */ - k_free(msg); return ret; } diff --git a/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.h b/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.h index 13f39ebef82c..921852392001 100644 --- a/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.h +++ b/samples/nrf9160/nrf_cloud_mqtt_multi_service/src/connection.h @@ -5,14 +5,14 @@ #ifndef _CONNECTION_H_ #define _CONNECTION_H_ -#include +#include /** * @brief nRF Cloud device message handler. * * @param[in] dev_msg The received device message as a NULL-terminated string */ -typedef void (*dev_msg_handler_cb_t)(const char * const dev_msg); +typedef void (*dev_msg_handler_cb_t)(const struct nrf_cloud_data *const dev_msg); /** * @brief Register a device message handler to receive general device messages from nRF Cloud @@ -90,19 +90,12 @@ bool await_date_time_known(k_timeout_t timeout); int consume_device_message(void); /** - * @brief Schedule a (null-terminated) string to be sent as a device message payload. Message will - * be held asynchronously until a valid nRF Cloud connection is established. The entire - * message is copied to the heap, so the original string passed need not be held onto. - * @return int - 0 on success, -ENOMEM if the outgoing message queue is full. - */ -int send_device_message(const char *const msg); - -/** - * @brief Schedule a cJSON object to be sent as a device message payload. Message will + * @brief Schedule a cloud object to be sent as a device message payload. Message will * be held asynchronously until a valid nRF Cloud connection is established. + * Caller is no longer responsible for device message memory after function returns. * @return int - 0 on success, otherwise negative error. */ -int send_device_message_cJSON(cJSON *msg_obj); +int send_device_message(struct nrf_cloud_obj *const msg_obj); /** * @brief The message queue thread function. From 176dc2337416388bce6aa23b83c3144a908a41b6 Mon Sep 17 00:00:00 2001 From: Justin Morton Date: Fri, 14 Apr 2023 14:47:14 -0700 Subject: [PATCH 2/3] applications: serial_lte_modem: use new nrf_cloud_obj struct Use new nrf_cloud_obj struct and related encoding and decoding functions. IRIS-6060 Signed-off-by: Justin Morton --- .../serial_lte_modem/src/gnss/slm_at_gnss.c | 149 +++++++----------- 1 file changed, 56 insertions(+), 93 deletions(-) diff --git a/applications/serial_lte_modem/src/gnss/slm_at_gnss.c b/applications/serial_lte_modem/src/gnss/slm_at_gnss.c index 709893581d8c..90700b9646fc 100644 --- a/applications/serial_lte_modem/src/gnss/slm_at_gnss.c +++ b/applications/serial_lte_modem/src/gnss/slm_at_gnss.c @@ -25,9 +25,6 @@ LOG_MODULE_REGISTER(slm_gnss, CONFIG_SLM_LOG_LEVEL); #define SERVICE_INFO_GNSS \ "{\"state\":{\"reported\":{\"device\": {\"serviceInfo\":{\"ui\":[\"GNSS\"]}}}}}" -#define MODEM_AT_RSP \ - "{\"appId\":\"MODEM\", \"messageType\":\"RSP\", \"data\":\"%s\"}" - #define LOCATION_REPORT_MS 5000 /**@brief GNSS operations. */ @@ -538,12 +535,11 @@ static void on_gnss_evt_pvt(void) } } -static int do_cloud_send_msg(const char *message, int len) +static int do_cloud_send_obj(struct nrf_cloud_obj *const obj) { int err; struct nrf_cloud_tx_data msg = { - .data.ptr = message, - .data.len = len, + .obj = obj, .topic_type = NRF_CLOUD_TOPIC_MESSAGE, .qos = MQTT_QOS_0_AT_MOST_ONCE }; @@ -553,6 +549,8 @@ static int do_cloud_send_msg(const char *message, int len) LOG_ERR("nrf_cloud_send failed, error: %d", err); } + (void)nrf_cloud_obj_free(obj); + return err; } @@ -560,13 +558,12 @@ static void send_location(struct nrf_modem_gnss_nmea_data_frame * const nmea_dat { static int64_t last_ts_ms = NRF_CLOUD_NO_TIMESTAMP; int err; - char *json_msg = NULL; - cJSON *msg_obj = NULL; struct nrf_cloud_gnss_data gnss = { .ts_ms = NRF_CLOUD_NO_TIMESTAMP, .type = NRF_CLOUD_GNSS_TYPE_MODEM_NMEA, .mdm_nmea = nmea_data }; + NRF_CLOUD_OBJ_JSON_DEFINE(msg_obj); /* On failure, NRF_CLOUD_NO_TIMESTAMP is used and the timestamp is omitted */ (void)date_time_now(&gnss.ts_ms); @@ -579,28 +576,10 @@ static void send_location(struct nrf_modem_gnss_nmea_data_frame * const nmea_dat return; } - msg_obj = cJSON_CreateObject(); - if (!msg_obj) { - return; - } - - err = nrf_cloud_gnss_msg_json_encode(&gnss, msg_obj); - if (err) { - goto clean_up; - } - - json_msg = cJSON_PrintUnformatted(msg_obj); - if (!json_msg) { - err = -ENOMEM; - goto clean_up; - } - - err = do_cloud_send_msg(json_msg, strlen(json_msg)); - -clean_up: - cJSON_Delete(msg_obj); - if (json_msg) { - cJSON_free((void *)json_msg); + /* Encode the location data into a device message */ + err = nrf_cloud_obj_gnss_msg_create(&msg_obj, &gnss); + if (!err) { + err = do_cloud_send_obj(&msg_obj); } if (err) { @@ -820,7 +799,7 @@ static void on_cloud_evt_location_data_received(const struct nrf_cloud_data *con static void cloud_cmd_wk(struct k_work *work) { int ret; - char *cmd_rsp; + NRF_CLOUD_OBJ_JSON_DEFINE(cmd_rsp_obj); ARG_UNUSED(work); @@ -839,83 +818,65 @@ static void cloud_cmd_wk(struct k_work *work) at_buf[i] = '\''; } } - /* format JSON reply */ - cmd_rsp = k_malloc(strlen(at_buf) + sizeof(MODEM_AT_RSP)); - if (cmd_rsp == NULL) { - LOG_WRN("Unable to allocate buffer"); + + ret = nrf_cloud_obj_msg_init(&cmd_rsp_obj, NRF_CLOUD_JSON_APPID_VAL_MODEM, "RSP"); + if (ret) { + LOG_WRN("Unable initialize AT response message"); return; } - sprintf(cmd_rsp, MODEM_AT_RSP, at_buf); + + ret = nrf_cloud_obj_str_add(&cmd_rsp_obj, NRF_CLOUD_JSON_DATA_KEY, at_buf, false); + if (ret) { + LOG_WRN("Unable to format AT response message"); + (void)nrf_cloud_obj_free(&cmd_rsp_obj); + return; + } + /* Send AT response to cloud */ - ret = do_cloud_send_msg(cmd_rsp, strlen(cmd_rsp)); + ret = do_cloud_send_obj(&cmd_rsp_obj); if (ret) { LOG_ERR("Send AT response to cloud error: %d", ret); } - k_free(cmd_rsp); } -static bool handle_cloud_cmd(const char *buf_in) +static bool handle_cloud_cmd(const struct nrf_cloud_data *const data) { - const cJSON *app_id = NULL; - const cJSON *msg_type = NULL; + struct nrf_cloud_obj input_obj; + char *at_cmd; bool ret = false; + int err = nrf_cloud_obj_input_decode(&input_obj, data); - cJSON *cloud_cmd_json = cJSON_Parse(buf_in); - - if (cloud_cmd_json == NULL) { - const char *error_ptr = cJSON_GetErrorPtr(); - - if (error_ptr != NULL) { - LOG_ERR("JSON parsing error before: %s", error_ptr); - } - goto end; - } - - app_id = cJSON_GetObjectItemCaseSensitive(cloud_cmd_json, NRF_CLOUD_JSON_APPID_KEY); - if (cJSON_GetStringValue(app_id) == NULL) { - goto end; - } - - /* Format expected from nrf cloud: - * {"appId":"MODEM", "messageType":"CMD", "data":""} - */ - if (strcmp(app_id->valuestring, NRF_CLOUD_JSON_APPID_VAL_MODEM) == 0) { - msg_type = cJSON_GetObjectItemCaseSensitive(cloud_cmd_json, - NRF_CLOUD_JSON_MSG_TYPE_KEY); - if (cJSON_GetStringValue(msg_type) != NULL) { - if (strcmp(msg_type->valuestring, NRF_CLOUD_JSON_MSG_TYPE_VAL_CMD) != 0) { - goto end; - } - } - - const cJSON *at_cmd = NULL; - - /* The value of attribute "data" contains the actual command */ - at_cmd = cJSON_GetObjectItemCaseSensitive(cloud_cmd_json, NRF_CLOUD_JSON_DATA_KEY); - if (cJSON_GetStringValue(at_cmd) != NULL) { - LOG_INF("MODEM CMD %s", at_cmd->valuestring); - strcpy(at_buf, at_cmd->valuestring); + if (err) { + LOG_ERR("Unable to decode data from nRF Cloud, error: %d", err); + return false; + } + + /* Check for a modem AT command message */ + err = nrf_cloud_obj_msg_check(&input_obj, + NRF_CLOUD_JSON_APPID_VAL_MODEM, + NRF_CLOUD_JSON_MSG_TYPE_VAL_CMD); + if (!err) { + err = nrf_cloud_obj_str_get(&input_obj, NRF_CLOUD_JSON_DATA_KEY, &at_cmd); + if (!err) { + LOG_INF("MODEM CMD %s", at_cmd); + strcpy(at_buf, at_cmd); k_work_submit_to_queue(&slm_work_q, &cloud_cmd); ret = true; } - /* Format expected from nrf cloud: - * {"appId":"DEVICE", "messageType":"DISCON"} - */ - } else if (strcmp(app_id->valuestring, NRF_CLOUD_JSON_APPID_VAL_DEVICE) == 0) { - msg_type = cJSON_GetObjectItemCaseSensitive(cloud_cmd_json, - NRF_CLOUD_JSON_MSG_TYPE_KEY); - if (cJSON_GetStringValue(msg_type) != NULL) { - if (strcmp(msg_type->valuestring, - NRF_CLOUD_JSON_MSG_TYPE_VAL_DISCONNECT) == 0) { - LOG_INF("DEVICE DISCON"); - /* No action required, handled in lib_nrf_cloud */ - ret = true; - } - } + goto end; } + /* Check for a disconnect message */ + err = nrf_cloud_obj_msg_check(&input_obj, + NRF_CLOUD_JSON_APPID_VAL_DEVICE, + NRF_CLOUD_JSON_MSG_TYPE_VAL_DISCONNECT); + if (!err) { + LOG_INF("DEVICE DISCON"); + /* No action required, handled in lib_nrf_cloud */ + ret = true; + } end: - cJSON_Delete(cloud_cmd_json); + (void)nrf_cloud_obj_free(&input_obj); return ret; } @@ -924,7 +885,7 @@ static void on_cloud_evt_data_received(const struct nrf_cloud_data *const data) if (nrf_cloud_ready) { if (((char *)data->ptr)[0] == '{') { /* Check if it's a cloud command sent from the cloud */ - if (handle_cloud_cmd(data->ptr)) { + if (handle_cloud_cmd(data)) { return; } } @@ -1005,7 +966,9 @@ static int nrf_cloud_datamode_callback(uint8_t op, const uint8_t *data, int len) int ret = 0; if (op == DATAMODE_SEND) { - ret = do_cloud_send_msg(data, len); + NRF_CLOUD_OBJ_PRE_ENC_DEFINE(obj, data, len); + + ret = do_cloud_send_obj(&obj); LOG_INF("datamode send: %d", ret); if (ret < 0) { (void)exit_datamode(ret); From 495b8d44b29ce99c525d3e802e2d0aab2b0189df Mon Sep 17 00:00:00 2001 From: Justin Morton Date: Mon, 17 Apr 2023 16:31:58 -0700 Subject: [PATCH 3/3] samples: modem_shell: use nrf_cloud library to create P-GPS request Use function in nrf_cloud_codec to create the nRF Cloud P-GPS request device message. IRIS-6060 Signed-off-by: Justin Morton --- doc/nrf/releases/release-notes-changelog.rst | 4 + .../src/location/location_srv_ext_nrf_cloud.c | 79 ++----------------- 2 files changed, 11 insertions(+), 72 deletions(-) diff --git a/doc/nrf/releases/release-notes-changelog.rst b/doc/nrf/releases/release-notes-changelog.rst index ed7e61041da6..ba2cd7f764bf 100644 --- a/doc/nrf/releases/release-notes-changelog.rst +++ b/doc/nrf/releases/release-notes-changelog.rst @@ -235,6 +235,10 @@ nRF9160 samples * Updated the sample to print its version when started. +* :ref:`modem_shell_application` sample: + + * The sample now uses the :ref:`lib_nrf_cloud` library function :c:func:`nrf_cloud_obj_pgps_request_create` to create a P-GPS request. + Trusted Firmware-M (TF-M) samples --------------------------------- diff --git a/samples/nrf9160/modem_shell/src/location/location_srv_ext_nrf_cloud.c b/samples/nrf9160/modem_shell/src/location/location_srv_ext_nrf_cloud.c index 9b93043f662d..012bf46db167 100644 --- a/samples/nrf9160/modem_shell/src/location/location_srv_ext_nrf_cloud.c +++ b/samples/nrf9160/modem_shell/src/location/location_srv_ext_nrf_cloud.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "mosh_print.h" @@ -38,81 +39,16 @@ void location_srv_ext_agps_handle(const struct nrf_modem_gnss_agps_data_frame *a void location_srv_ext_pgps_handle(const struct gps_pgps_request *pgps_req) { int err = 0; - cJSON *data_obj; - cJSON *pgps_req_obj; - cJSON *ret; - cJSON *appid_key; - cJSON *msg_type_key; - char *msg_string = NULL; - - /* Encode P-GPS request */ - pgps_req_obj = cJSON_CreateObject(); - if (pgps_req_obj == NULL) { - err = -ENOMEM; - goto cleanup; - } - - appid_key = cJSON_AddStringToObjectCS(pgps_req_obj, NRF_CLOUD_JSON_APPID_KEY, - NRF_CLOUD_JSON_APPID_VAL_PGPS); - if (appid_key == NULL) { - mosh_error("Failed to add application id to P-GPS request"); - err = -ENOMEM; - goto cleanup; - } - msg_type_key = cJSON_AddStringToObjectCS(pgps_req_obj, NRF_CLOUD_JSON_MSG_TYPE_KEY, - NRF_CLOUD_JSON_MSG_TYPE_VAL_DATA); - if (msg_type_key == NULL) { - mosh_error("Failed to add message type to P-GPS request"); - err = -ENOMEM; - goto cleanup; - } - - data_obj = cJSON_AddObjectToObject(pgps_req_obj, NRF_CLOUD_JSON_DATA_KEY); - if (data_obj == NULL) { - mosh_error("Failed to add pred count to P-GPS request"); - err = -ENOMEM; - goto cleanup; - } + NRF_CLOUD_OBJ_JSON_DEFINE(pgps_obj); - ret = cJSON_AddNumberToObject(data_obj, NRF_CLOUD_JSON_PGPS_PRED_COUNT, - pgps_req->prediction_count); - if (ret == NULL) { - mosh_error("Failed to add pred count to P-GPS request"); - err = -ENOMEM; - goto cleanup; - } - ret = cJSON_AddNumberToObject(data_obj, NRF_CLOUD_JSON_PGPS_INT_MIN, - pgps_req->prediction_period_min); - if (ret == NULL) { - mosh_error("Failed to add pred int min to P-GPS request"); - err = -ENOMEM; - goto cleanup; - } - ret = cJSON_AddNumberToObject(data_obj, NRF_CLOUD_JSON_PGPS_GPS_DAY, - pgps_req->gps_day); - if (ret == NULL) { - mosh_error("Failed to add GPS day to P-GPS request"); - err = -ENOMEM; - goto cleanup; - } - ret = cJSON_AddNumberToObject(data_obj, NRF_CLOUD_JSON_PGPS_GPS_TIME, - pgps_req->gps_time_of_day); - if (ret == NULL) { - mosh_error("Failed to add GPS time to P-GPS request"); - err = -ENOMEM; - goto cleanup; - } - - /* Convert CJSON object to string and send to nRF Cloud */ - msg_string = cJSON_PrintUnformatted(pgps_req_obj); - if (msg_string == NULL) { - mosh_error("Could not allocate memory for request message"); + err = nrf_cloud_obj_pgps_request_create(&pgps_obj, pgps_req); + if (err) { + mosh_error("Could not create P-GPS request message, error: %d", err); goto cleanup; } struct nrf_cloud_tx_data mqtt_msg = { - .data.ptr = msg_string, - .data.len = strlen(msg_string), + .obj = &pgps_obj, .qos = MQTT_QOS_1_AT_LEAST_ONCE, .topic_type = NRF_CLOUD_TOPIC_MESSAGE, }; @@ -123,8 +59,7 @@ void location_srv_ext_pgps_handle(const struct gps_pgps_request *pgps_req) } cleanup: - cJSON_Delete(pgps_req_obj); - cJSON_free(msg_string); + (void)nrf_cloud_obj_free(&pgps_obj); if (err) { mosh_error("nRF Cloud P-GPS request failed, error: %d", err);