Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1927,8 +1927,20 @@ static void fota_rebooting_entry(void *o)
{
ARG_UNUSED(o);

struct storage_msg msg = { .type = STORAGE_CLEAR };
int err;

LOG_DBG("%s", __func__);

/* Tell storage module to clear any stored data */
err = zbus_chan_pub(&STORAGE_CHAN, &msg, K_MSEC(ZBUS_PUBLISH_TIMEOUT_MS));
if (err) {
LOG_ERR("Failed to publish storage clear message, error: %d", err);
SEND_FATAL_ERROR();

return;
}

/* Reboot the device */
LOG_WRN("Rebooting the device to apply the FOTA update");

Expand Down
29 changes: 29 additions & 0 deletions app/src/modules/cloud/Kconfig.cloud
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,35 @@ config APP_CLOUD_BACKOFF_MAX_SECONDS
help
Maximum reconnection backoff value in seconds.

choice APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS
prompt "Handling of wrong timestamps in data samples"
default APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_DROP

config APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_DROP
bool "Drop data samples with wrong timestamps"
help
Data samples with wrong timestamps will be dropped and not sent to the cloud.

config APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_KEEP
bool "Keep data samples with wrong timestamps"
help
Data samples with wrong timestamps will be kept and sent to the cloud as is.

config APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_NOW
bool "Set timestamp to current time"
help
Data samples with wrong timestamps will have their timestamps set to the current time
before being sent to the cloud.

config APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_NO_TIMESTAMP
bool "Set timestamp to NO_TIMESTAMP"
help
Data samples with wrong timestamps will have their timestamps set to NO_TIMESTAMP
before being sent to the cloud. For nRF Cloud, this means the cloud will set the timestamp
to the time of reception.

endchoice

config APP_CLOUD_THREAD_STACK_SIZE
int "Thread stack size"
default 5120
Expand Down
54 changes: 42 additions & 12 deletions app/src/modules/cloud/cloud.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,36 @@ static void send_request_failed(void)
}
}

static int handle_data_timestamp(int64_t *timestamp_ms)
{
int err;

/* Soft attempt to convert uptime to unix time, keep original value on failure */
err = attempt_timestamp_to_unix_ms(timestamp_ms);
if (err == 0 || err == -EALREADY) {
return 0;
}

if (IS_ENABLED(CONFIG_APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_KEEP)) {
LOG_WRN("Keeping original timestamp value");
return 0;
} else if (IS_ENABLED(CONFIG_APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_NOW)) {
*timestamp_ms = k_uptime_get();
err = attempt_timestamp_to_unix_ms(timestamp_ms);
if (err) {
LOG_ERR("Failed to set timestamp to current time, error: %d", err);
return err;
}
LOG_WRN("Setting timestamp to current time");
return 0;
} else if (IS_ENABLED(CONFIG_APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_NO_TIMESTAMP)) {
*timestamp_ms = NRF_CLOUD_NO_TIMESTAMP;
return 0;
} else { /* Default behavior: APP_CLOUD_HANDLE_WRONG_SAMPLE_TIMESTAMPS_DROP */
return err;
}
}

static void handle_network_data_message(const struct network_msg *msg)
{
int err;
Expand All @@ -347,11 +377,11 @@ static void handle_network_data_message(const struct network_msg *msg)
return;
}

/* Convert uptime to unix time */
timestamp_ms = msg->uptime;
err = date_time_uptime_to_unix_time_ms(&timestamp_ms);
/* Convert timestamp to unix time */
timestamp_ms = msg->timestamp;
err = handle_data_timestamp(&timestamp_ms);
if (err) {
LOG_ERR("date_time_uptime_to_unix_time_ms, error: %d", err);
return;
}

err = nrf_cloud_coap_sensor_send(CUSTOM_JSON_APPID_VAL_CONEVAL,
Expand Down Expand Up @@ -387,11 +417,11 @@ static int send_storage_data_to_cloud(const struct storage_data_item *item)
if (item->type == STORAGE_TYPE_BATTERY) {
const struct power_msg *power = &item->data.BATTERY;

/* Convert uptime to unix time */
timestamp_ms = power->uptime;
err = date_time_uptime_to_unix_time_ms(&timestamp_ms);
/* Convert timestamp to unix time */
timestamp_ms = power->timestamp;
err = handle_data_timestamp(&timestamp_ms);
if (err) {
LOG_ERR("date_time_uptime_to_unix_time_ms, error: %d", err);
return err;
}

err = nrf_cloud_coap_sensor_send(CUSTOM_JSON_APPID_VAL_BATTERY,
Expand All @@ -416,11 +446,11 @@ static int send_storage_data_to_cloud(const struct storage_data_item *item)
if (item->type == STORAGE_TYPE_ENVIRONMENTAL) {
const struct environmental_msg *env = &item->data.ENVIRONMENTAL;

/* Convert uptime to unix time */
timestamp_ms = env->uptime;
err = date_time_uptime_to_unix_time_ms(&timestamp_ms);
/* Convert timestamp to unix time */
timestamp_ms = env->timestamp;
err = handle_data_timestamp(&timestamp_ms);
if (err) {
LOG_ERR("date_time_uptime_to_unix_time_ms, error: %d", err);
return err;
}

return cloud_environmental_send(env, timestamp_ms, confirmable);
Expand Down
41 changes: 41 additions & 0 deletions app/src/modules/cloud/cloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <zephyr/kernel.h>
#include <zephyr/zbus/zbus.h>
#include <date_time.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -127,6 +128,46 @@ struct cloud_msg {

#define MSG_TO_CLOUD_MSG_PTR(_msg) ((const struct cloud_msg *)_msg)

#define UNIX_TIME_MS_2026_01_01 1767222000000LL
/**
* @brief Attempt to set the provided uptime (in milliseconds) to unix time.
*
* Tries to convert the provided timestamp from uptime to unix time in milliseconds, if needed.
* If it cant convert it will stay unchanged.
*
* @param uptime_ms Uptime to convert to unix time.
* @return int 0 if conversion was successful,
* -EINVAL if the provided pointer is NULL,
* -EALREADY if the provided time was already in unix time (>= 2026-01-01),
* -ENODATA if date time is not valid,
*/
static inline int64_t attempt_timestamp_to_unix_ms(int64_t *uptime_ms)
{
int err;

if (uptime_ms == NULL) {
return -EINVAL;
}
if (*uptime_ms >= UNIX_TIME_MS_2026_01_01) {
/* Already unix time */
return -EALREADY;
}
if (*uptime_ms > k_uptime_get()) {
/* Uptime cannot be in the future */
return -EINVAL;
}

if (!date_time_is_valid()) {
/* Cannot convert without valid time */
return -ENODATA;
}
err = date_time_uptime_to_unix_time_ms(uptime_ms);
if (err) {
return err;
}
return 0;
}

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion app/src/modules/cloud/cloud_location.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ static void handle_gnss_location_data(const struct location_msg *location_msg)
const struct location_data *location_data = &location_msg->gnss_data;

/* Convert uptime to unix time */
timestamp_ms = location_msg->uptime;
timestamp_ms = location_msg->timestamp;
err = date_time_uptime_to_unix_time_ms(&timestamp_ms);
if (err) {
LOG_ERR("date_time_uptime_to_unix_time_ms, error: %d", err);
Expand Down
10 changes: 9 additions & 1 deletion app/src/modules/environmental/environmental.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <zephyr/drivers/sensor.h>
#include <zephyr/task_wdt/task_wdt.h>
#include <zephyr/smf.h>
#include <date_time.h>

#include "app_common.h"
#include "environmental.h"
Expand Down Expand Up @@ -118,9 +119,16 @@ static void sample_sensors(const struct device *const bme680)
.temperature = sensor_value_to_double(&temp),
.pressure = sensor_value_to_double(&press),
.humidity = sensor_value_to_double(&humidity),
.uptime = k_uptime_get(),
.timestamp = k_uptime_get(),
};

err = date_time_now(&msg.timestamp);
if (err != 0 && err != -ENODATA) {
LOG_ERR("date_time_now, error: %d", err);
SEND_FATAL_ERROR();
return;
}

/* Log the environmental values and limit to 2 decimals */
LOG_DBG("Temperature: %.2f C, Pressure: %.2f Pa, Humidity: %.2f %%",
msg.temperature, msg.pressure, msg.humidity);
Expand Down
9 changes: 5 additions & 4 deletions app/src/modules/environmental/environmental.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ struct environmental_msg {
/** Contains the current pressure in Pa. */
double pressure;

/** Uptime when the sample was taken in milliseconds.
* Use date_time_uptime_to_unix_time_ms() to convert to unix time before sending to cloud.
* Only valid for ENVIRONMENTAL_SENSOR_SAMPLE_RESPONSE events.
/** Timestamp when the sample was taken in milliseconds.
* This is either:
* - Unix time in milliseconds if the system clock was synchronized at sampling time, or
* - Uptime in milliseconds if the system clock was not synchronized at sampling time.
*/
int64_t uptime;
int64_t timestamp;
};

#define MSG_TO_ENVIRONMENTAL_MSG(_msg) (*(const struct environmental_msg *)_msg)
Expand Down
9 changes: 8 additions & 1 deletion app/src/modules/location/location.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,16 @@ static void gnss_location_send(const struct location_data *location_data)
struct location_msg location_msg = {
.type = LOCATION_GNSS_DATA,
.gnss_data = *location_data,
.uptime = k_uptime_get()
.timestamp = k_uptime_get()
};

err = date_time_now(&location_msg.timestamp);
if (err != 0 && err != -ENODATA) {
LOG_ERR("date_time_now, error: %d", err);
SEND_FATAL_ERROR();
return;
}

err = zbus_chan_pub(&LOCATION_CHAN, &location_msg, K_SECONDS(1));
if (err) {
LOG_ERR("zbus_chan_pub, error: %d", err);
Expand Down
9 changes: 5 additions & 4 deletions app/src/modules/location/location.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,12 @@ struct location_msg {
struct location_data gnss_data;
};

/** Uptime when the location was obtained in milliseconds.
* Use date_time_uptime_to_unix_time_ms() to convert to unix time before sending to cloud.
* Only valid for LOCATION_GNSS_DATA events.
/** Timestamp when the sample was taken in milliseconds.
* This is either:
* - Unix time in milliseconds if the system clock was synchronized at sampling time, or
* - Uptime in milliseconds if the system clock was not synchronized at sampling time.
*/
int64_t uptime;
int64_t timestamp;
};

#define MSG_TO_LOCATION_TYPE(_msg) (((const struct location_msg *)_msg)->type)
Expand Down
9 changes: 8 additions & 1 deletion app/src/modules/network/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,16 @@ static void sample_network_quality(void)
int ret;
struct network_msg msg = {
.type = NETWORK_QUALITY_SAMPLE_RESPONSE,
.uptime = k_uptime_get()
.timestamp = k_uptime_get()
};

ret = date_time_now(&msg.timestamp);
if (ret != 0 && ret != -ENODATA) {
LOG_ERR("date_time_now, error: %d", ret);
SEND_FATAL_ERROR();
return;
}

ret = lte_lc_conn_eval_params_get(&msg.conn_eval_params);
if (ret == -EOPNOTSUPP) {
LOG_WRN("Connection evaluation not supported in current functional mode");
Expand Down
9 changes: 5 additions & 4 deletions app/src/modules/network/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,12 @@ struct network_msg {
(struct lte_lc_conn_eval_params conn_eval_params));
};

/** Uptime when the sample was taken in milliseconds.
* Use date_time_uptime_to_unix_time_ms() to convert to unix time before sending to cloud.
* Only valid for NETWORK_QUALITY_SAMPLE_RESPONSE events.
/** Timestamp when the sample was taken in milliseconds.
* This is either:
* - Unix time in milliseconds if the system clock was synchronized at sampling time, or
* - Uptime in milliseconds if the system clock was not synchronized at sampling time.
*/
int64_t uptime;
int64_t timestamp;
};

#define MSG_TO_NETWORK_MSG(_msg) (*(const struct network_msg *)_msg)
Expand Down
10 changes: 9 additions & 1 deletion app/src/modules/power/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <zephyr/task_wdt/task_wdt.h>
#include <zephyr/smf.h>
#include <modem/nrf_modem_lib_trace.h>
#include <date_time.h>

#include "lp803448_model.h"
#include "app_common.h"
Expand Down Expand Up @@ -441,9 +442,16 @@ static void sample(int64_t *ref_time)
.percentage = (double)roundf(state_of_charge),
.charging = charging,
.voltage = (double)voltage,
.uptime = k_uptime_get()
.timestamp = k_uptime_get()
};

err = date_time_now(&msg.timestamp);
if (err != 0 && err != -ENODATA) {
LOG_ERR("date_time_now, error: %d", err);
SEND_FATAL_ERROR();
return;
}

err = zbus_chan_pub(&POWER_CHAN, &msg, K_NO_WAIT);
if (err) {
LOG_ERR("zbus_chan_pub, error: %d", err);
Expand Down
9 changes: 5 additions & 4 deletions app/src/modules/power/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ struct power_msg {
/** Voltage in volts. */
double voltage;

/** Uptime when the sample was taken in milliseconds.
* Use date_time_uptime_to_unix_time_ms() to convert to unix time before sending to cloud.
* Only valid for POWER_BATTERY_PERCENTAGE_SAMPLE_RESPONSE events.
/** Timestamp when the sample was taken in milliseconds.
* This is either:
* - Unix time in milliseconds if the system clock was synchronized at sampling time, or
* - Uptime in milliseconds if the system clock was not synchronized at sampling time.
*/
int64_t uptime;
int64_t timestamp;
};

#define MSG_TO_POWER_MSG(_msg) (*(const struct power_msg *)_msg)
Expand Down
3 changes: 3 additions & 0 deletions app/src/modules/storage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ zephyr_linker_sources(SECTIONS storage_sections.ld)
target_sources_ifdef(CONFIG_APP_STORAGE_BACKEND_RAM app PRIVATE
backends/ram_ring_buffer_backend.c
)
target_sources_ifdef(CONFIG_APP_STORAGE_BACKEND_LITTLEFS app PRIVATE
backends/littlefs_backend.c
)

target_sources_ifdef(CONFIG_APP_STORAGE_SHELL app PRIVATE
storage_shell.c
Expand Down
Loading
Loading