Git Product home page Git Product logo

spiffs_circular_queue's Introduction

SPIFFS Circular Queue

SPIFFS Circular Queue or Circular FIFO Buffer is a data structure similar to a regular array queue in which the last data byte is connected to the first data byte. The queue metadata is maintained through circular_queue_t struct in RAM and are kept up to date in queue header in SPIFFS. Refer to circular_queue_t definition to see precisely what is stored in RAM. On the other hand, special effort was put to optimize non-volatile (nv) footprint.

Queue max size is settable for each queue instance through max_size member of circular_queue_t. Elems can be of variable or fixed size. If elems are of variable size (elem_size = 0), the elem size is stored at the beginning of each elem. If elem size if fixed (elem_size > 0), no elem size is stored.

Elems size of a variable elem size queue can also be limited, if you find it useful to keep it under control. Set SPIFFS_CIRCULAR_QUEUE_MAX_ELEM_SIZE to a max size in bytes you may want, and when you want to enqueue an elem size that exceeds the SPIFFS_CIRCULAR_QUEUE_MAX_ELEM_SIZE value it will be truncated. If you want to keep it unconstraint, just keep it on zero.

Basic nv structure is split in two parts: metadata header and data body. The header is composed of a fixed (always-stored) and optional parts. Optional part is stored iff optional feature(s) is/are enabled. Metadata header is depicted below.

┌─────────────┬────────────┬───────────┬───────────┬──────────┬─ ─ ─ ─ ─ ─┐
│ front index | back index |   count   | max size  |   flags  | elem size |
|  (4 bytes)  | (4 bytes)  | (2 bytes) | (4 bytes) | (1 byte) | (2 bytes) |
└─────────────┴────────────┴───────────┴───────────┴──────────┴─ ─ ─ ─ ─ ─┘
 \_____________________________._____________________________/ \____.____/
                           fixed part                          optional part

The flags is a one-byte bitfield with the following information

┌─────────────────┬──────────┬────────────┐
│ fixed elem size | reserved | queue type |
|     (1 bit)     | (3 bits) |  (4 bits)  |
└─────────────────┴──────────┴────────────┘

Data body can follow two patterns depending if the queue elem size is variable or fixed.

┌─────────────┬────────┬───────┬─────────────┬────────┐    ┌────────┬───────┬────────┐
│ 1 elem size | 1 elem |  ...  | n elem size | n elem |    │ 1 elem |  ...  | n elem |
|  (4 bytes)  |  data  |       |  (2 bytes)  |  data  |    |  data  |       |  data  |
└─────────────┴────────┴───────┴─────────────┴────────┘    └────────┴───────┴────────┘
 \_________________________._________________________/      \___________.___________/
             variable elem size data body                   fixed elem size data body 

Fixed metadata header is used to keep track of queue pointers and allows to fully restore the queue after a power loss or (un)expected reset. Nodes may vary in size what comes very handy when you need to store network packets or any data of variable size. If your data of fixed size like timestamps or sensor readings, this project is a good fit for you as well.

It was carefully unit-tested on ESP32 considering important general and corner cases. To see testes cases refer to unit_testing/test_main.ino.

Interface

spiffs_circular_queue_init

Initializes the library creating/reading a spiffs data file. Sets current front, back, and count queue indices. For non-volatile storages the initialization and re-initialization depend on the written queue data. The library will set its indices and count variables to what is encounted on the medium or set to zeros if found none. If you modify cq struct variables outside of the library, that will be lost if _persist function will not be called. Initialization will result in failure only on null cq struct pointer, failure to mount SPIFFS, or failure to write queue data file on SPIFFS.

uint8_t spiffs_circular_queue_init(circular_queue_t *cq);

Returns 1 on success and 0 on fail.

spiffs_circular_queue_front

Places front queue elem of elem_size size to the elem.

uint8_t spiffs_circular_queue_front(const circular_queue_t *cq, void *elem = NULL, uint16_t *elem_size = NULL);
cq->front(const circular_queue_t *cq, void *elem, uint16_t *elem_size); // variable elem size
cq->front(const circular_queue_t *cq, void *elem, NULL /* don't care */); // fixed elem size

Returns 1 on success and 0 on fail.

spiffs_circular_queue_enqueue

Enqueues elem of elem_size size to the front of the queue if there is enough room in the queue. Be responsible for passing elem buffer of SPIFFS_CIRCULAR_QUEUE_MAX_ELEM_SIZE size or less if SPIFFS_CIRCULAR_QUEUE_MAX_ELEM_SIZE is enabled.

uint8_t spiffs_circular_queue_enqueue(circular_queue_t *cq, const void *elem = NULL, const uint16_t elem_size = 0);
cq->enqueue(circular_queue_t *cq, const void *elem, const uint16_t elem_size); // variable elem size
cq->enqueue(circular_queue_t *cq, const void *elem, 0 /* don't care */); // fixed elem size

Returns 1 on success and 0 on fail.

spiffs_circular_queue_dequeue

Pops out the first elem of the queue. When elem and elem_size are valid pointers, front elem is placed in them and then it pops out.

uint8_t spiffs_circular_queue_dequeue(circular_queue_t *cq, void *elem = NULL, uint16_t *elem_size = NULL);
cq->dequeue(circular_queue_t *cq, void *elem, uint16_t elem_size); // variable elem size
cq->dequeue(circular_queue_t *cq, void *elem, NULL /* don't care */); // fixed elem size

Returns 1 on success and 0 on fail.

spiffs_circular_queue_is_empty

Checks whether the queue is empty or not.

uint8_t spiffs_circular_queue_is_empty(const circular_queue_t *cq);
cq->is_empty(const circular_queue_t *cq);

Returns 1 when empty and 0 if not.

spiffs_circular_queue_size

Returns the current queue net data size. This function is useful when you need to know how much pure data you still need to process/send. It does not account nodes sizes stored at head of each node.

uint32_t spiffs_circular_queue_size(const circular_queue_t *cq);
cq->size(const circular_queue_t *cq);

Returns the current queue net data size.

spiffs_circular_queue_available_space

Returns queue available space in bytes. Allows to return a real estimate for the next elem to be enqueued. Caution: not upper limited by the SPIFFS_CIRCULAR_QUEUE_MAX_ELEM_SIZE. Check SPIFFS_CIRCULAR_QUEUE_MAX_ELEM_SIZE value to see max elem size you can enqueue if enabled.

uint32_t spiffs_circular_queue_available_space(const circular_queue_t *cq);
cq->available_space(const circular_queue_t *cq);

Returns queue available space in bytes.

spiffs_circular_queue_get_front_idx

Gets the front index of the queue.

uint32_t spiffs_circular_queue_get_front_idx(const circular_queue_t *cq);
cq->get_front_idx(const circular_queue_t *cq);

Returns front index in bytes.

spiffs_circular_queue_get_back_idx

Gets the back index of the queue.

uint32_t spiffs_circular_queue_get_back_idx(const circular_queue_t *cq);
cq->get_back_idx(const circular_queue_t *cq);

Returns back index in bytes.

spiffs_circular_queue_get_count

Gets the queue nodes count.

uint16_t spiffs_circular_queue_get_count(const circular_queue_t *cq);
cq->get_count(const circular_queue_t *cq);

Returns queue nodes count.

spiffs_circular_queue_get_file_size

Gets the queue SPIFFS file footprint in bytes.

uint32_t spiffs_circular_queue_get_file_size(const circular_queue_t *cq);
cq->get_file_size(const circular_queue_t *cq);

Returns queue SPIFFS file size in bytes.

spiffs_circular_queue_free

Frees resourses allocated for the queue and closes the SPIFFS.

uint8_t	spiffs_circular_queue_free(circular_queue_t *cq, const uint8_t unmount_spiffs = 1);
cq->free(circular_queue_t *cq, const uint8_t unmount_spiffs = 1);

Returns 1 on success and 0 on fail.

Typical example

Multiple instances of different queues can peacefully coexist. This is a typical example.

#include <Arduino.h>
#include "spiffs_circular_queue.h"

circular_queue_t cq_variable;   // variable elem size
circular_queue_t cq_fixed;      // fixed elem size

void setup() {
    // Very important point to get right filename
    //   queues are distinguished by filenames. 
    //   Don't forget '/spiffs/' prefix!
    snprintf(cq_variable.fn, SPIFFS_FILE_NAME_MAX_SIZE, "/spiffs/variable");
    cq_variable.max_size = 2048;
    spiffs_circular_queue_init(&cq_variable);

    snprintf(cq_fixed.fn, SPIFFS_FILE_NAME_MAX_SIZE, "/spiffs/variable");
    cq_fixed.elem_size = sizeof(uint64_t);
    cq_fixed.max_size = sizeof(uint64_t)*100;
    spiffs_circular_queue_init(&cq_fixed);
}

void loop() {
    uint8_t buf[128] = {1, 2, 3};
    uint16_t buf_len = 3;

    uint64_t elem = 4223;

    spiffs_circular_queue_enqueue(&cq_variable, buf, buf_len);
    spiffs_circular_queue_enqueue(&cq_fixed, &elem);
    
    //...
    // If necessary go to sleep. All data are safe in SPIFFS     
    //...

    // Flush the queue
    spiffs_circular_queue_foreach_dequeue(&cq_variable, buf, &buf_len) {
        // process each buf in the queue
    }

    spiffs_circular_queue_foreach_dequeue(&cq_fixed, &elem) {
        // process each elem in the queue
    }

    // Go to sleep again if necessary
    
    // If you need to remove queue from the spiffs for whatever reason...
    spiffs_circular_queue_free(&cq_variable);
    spiffs_circular_queue_free(&cq_fixed);
    // BE CAREFULL, you will lost all your enqueued data if some, and
    //  the circular_queue_t struct will be zeroed.
}

SPIFFS Consideration

The library will reliably work as far as you keep the used (or intended to be used) space under 75% of assigned to SPIFFS partition.

Attribution

If this project gets someone's appreciation, I want to transfer this appreciation to my God, Lord Jesus Christ.

License

The source code for the project is licensed under the MIT license, which you can find in the LICENSE.txt file.

spiffs_circular_queue's People

Contributors

rykovv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

spiffs_circular_queue's Issues

Add library.properties file

Add library.properties file containing essentially the same information as library.json, but for those unenlightened tools which do not know how to deal with JSON (Microsoft - polite nudge in your direction). Simplifies having the library recognised :-)

library.properties.zip

Define file max size dynamically as part of circular_queue_t

May I suggest that instead of defining file max size as a global fixed value (SPIFFS_CIRCULAR_QUEUE_FILE_MAX_SIZE), it should be defined as part of circular_queue_t, so could be set individually and dynamically for different queues. I have a requirement for queues with different sizes (completely different types of data), also where the file size is controlled dynamically based on availability of SPIFFS space (and reajusted regularly based on situation)

Some doubts regarding the Library

Dear @rykovv, Thank you for your support. I have a couple of questions regarding this library :

For me my application is to use this concept of circular queue to store data when the network is down. My data is 1KB of size in each message, I am planning to keep the size of 8MB for buffer memory which will be sufficient to store data for an adequate days.

  1. Plz give some of your suggession on this?
  2. Can I use the circular buffer memory to a particular file name.
  3. Can the size can be 8MB?

Documentation

Thanq for your great library, Can u plz include documentation and an example code, So that for us that will be helpful

E (29) SPIFFS: spiffs partition could not be found

Good morning dear, the library seems to be spectacular, we are trying to implement it in a device where we need to store data when we lose connection to a mqtt server but when trying to test the examples we find the following error:

E (29) SPIFFS: spiffs partition could not be found

We have uploaded the image several times on two different models, on a 16Mb esp32 using the CSV file and on a 4Mb esp32 using only Arduino but we can't get it to work.

Do you have any instructions to format the flash and make it suitable to use your library?

Thank you very much for your time and dedication in this bookstore.

Kind regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.