Skip to content

Conversation

@Trond-F-Christiansen
Copy link
Contributor

Adds littlefs based flash backend for the storage module

@Trond-F-Christiansen Trond-F-Christiansen force-pushed the storage-flash-backend branch 5 times, most recently from 02da245 to 930471b Compare January 15, 2026 12:08
@SyverHaraldsen SyverHaraldsen self-requested a review January 15, 2026 12:29
* -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the ifs be spaced?

target_sources_ifdef(CONFIG_APP_STORAGE_BACKEND_LITTLEFS app PRIVATE
backends/littlefs_backend.c
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space

/* Drop oldest when full to overwrite */
header.read_offset++;
LOG_WRN("Storage file %s full, overwriting oldest data", file_path);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space

Comment on lines +360 to +406
LOG_WRN("Setting timestamp to current time");
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LOG_WRN("Setting timestamp to current time");
return 0;
LOG_WRN("Setting timestamp to current time");
return 0;

Comment on lines +363 to +409
*timestamp_ms = NRF_CLOUD_NO_TIMESTAMP;
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*timestamp_ms = NRF_CLOUD_NO_TIMESTAMP;
return 0;
*timestamp_ms = NRF_CLOUD_NO_TIMESTAMP;
return 0;

Comment on lines 381 to 432
timestamp_ms = msg->timestamp;
err = handle_data_timestamp(&timestamp_ms);
if (err) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
timestamp_ms = msg->timestamp;
err = handle_data_timestamp(&timestamp_ms);
if (err) {
timestamp_ms = msg->timestamp;
err = handle_data_timestamp(&timestamp_ms);
if (err) {

Comment on lines +351 to +395
LOG_WRN("Keeping original timestamp value");
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LOG_WRN("Keeping original timestamp value");
return 0;
LOG_WRN("Keeping original timestamp value");
return 0;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicks incoming, will not comment on them all

Comment on lines 354 to 400
*timestamp_ms = k_uptime_get();
err = attempt_timestamp_to_unix_ms(timestamp_ms);
if (err) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*timestamp_ms = k_uptime_get();
err = attempt_timestamp_to_unix_ms(timestamp_ms);
if (err) {
*timestamp_ms = k_uptime_get();
err = attempt_timestamp_to_unix_ms(timestamp_ms);
if (err) {

static void create_storage_file_path(const struct storage_data *type, char *out_path,
size_t max_len)
{
snprintf(out_path, max_len, "%s/%s.bin", mountpoint.mnt_point, type->name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
snprintf(out_path, max_len, "%s/%s.bin", mountpoint.mnt_point, type->name);
err = snprintk(out_path, max_len, "%s/%s.bin", mountpoint.mnt_point, type->name);

Return value should be checked, so this function should probably return an int

max_records_per_type = total_storage_size / total_data_size;

if (max_records_per_type < RECORDS_PER_TYPE) {
LOG_WRN("Configured max records per type (%d) exceeds calculated capacity (%d). "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log message takes up a decent amount of flash, could it be compressed?

ssize_t rc;

/* If data is NULL, use temporary buffer to verify data exists */
uint8_t temp_buffer[type->data_size];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to make this static to avoid blowing up the stack

return -EINVAL;
}

/* Open storage file */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function needs some air in form of blank lines

ssize_t rc;

if (!type) {
return -EINVAL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could even assert here, it's a programming error that should not happen when a static function is called with invalid arguments

Copy link
Contributor

@SyverHaraldsen SyverHaraldsen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really good, and super cool.
Just nit-pick; there are a few places with inconsistent spacing. Pointed out just a couple.

@Trond-F-Christiansen Trond-F-Christiansen force-pushed the storage-flash-backend branch 2 times, most recently from c6ab86c to cee43d6 Compare January 15, 2026 14:24
Changes module msg timestamps to unix time at sample creation if
possible. If conversion fails, original uptime value is kept.
Reattempts conversion if needed before sending to cloud, if still not
possible handle error based on Kconfig setting.

Signed-off-by: Trond F. Christiansen <[email protected]>
Remove the unused memory slabs from the storage_data struct, and its
alocation.

Signed-off-by: Trond F. Christiansen <[email protected]>
Add littleFS based flash storage backend for the storage module.
Uses a file per storage data type to store a circular buffer of records.

Signed-off-by: Trond F. Christiansen <[email protected]>
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
41.9% Coverage on New Code (required ≥ 50%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants