In this tutorial, a simple but useful data buffering/streaming algorithm is presented. It is not optimal but easy to understand and modify according to your needs… This library assumes that we need to use a big amount of data in a memory limited system.
The library handles the all the data transferring procedure in a way that the user is able to easily get the amount of data without worrying about the buffering complexity.
#pragma once #include <stdio.h> #include <string.h> #include <inttypes.h> #define DATA_STREAM_DEVICE_START_ADDRESS 0 #define DATA_STREAM_DEVICE_END_ADDRESS 10000 #define DATA_STREAM_PAGE_SIZE 6 #define DATA_STREAM_IN_CENTERED typedef struct { uint32_t start_address; uint32_t size; uint8_t data[DATA_STREAM_PAGE_SIZE]; }data_stream_page_t; extern void (*data_stream_load_hk)(int start_address, int end_address, int size, uint8_t* buffer); uint8_t data_stream_init(); int data_stream_get(uint32_t address, uint16_t requested_size, uint8_t* buffer);
#include "data_stream.h" static data_stream_page_t page; void (*data_stream_load_hk)(int start_address, int end_address, int size); uint8_t data_stream_init() { page.start_address = 0; page.size = 0; memset(page.data, '0', DATA_STREAM_PAGE_SIZE); return 0; } static void reload_buffer(int requested_start_address, int requested_size) { if (requested_start_address < DATA_STREAM_DEVICE_START_ADDRESS) { data_stream_init(); return; } int device_start_address = requested_start_address - DATA_STREAM_DEVICE_START_ADDRESS; int device_end_address = (requested_start_address + DATA_STREAM_PAGE_SIZE) > DATA_STREAM_DEVICE_END_ADDRESS ? DATA_STREAM_DEVICE_END_ADDRESS : (requested_start_address + DATA_STREAM_PAGE_SIZE); int device_reqdata_size = device_end_address - device_start_address; #ifdef DATA_STREAM_IN_CENTERED int extra_retdata_size = (device_end_address - device_start_address) - requested_size; int extra_retdata_size_div2 = extra_retdata_size / 2; if (extra_retdata_size_div2 != 0 && extra_retdata_size != 0) { // at the beginning if (requested_start_address < extra_retdata_size_div2) { extra_retdata_size_div2 = requested_start_address; extra_retdata_size = 2 * extra_retdata_size_div2; device_start_address = 0; device_end_address = (requested_start_address + DATA_STREAM_PAGE_SIZE) > DATA_STREAM_DEVICE_END_ADDRESS ? DATA_STREAM_DEVICE_END_ADDRESS : (requested_start_address + DATA_STREAM_PAGE_SIZE); device_reqdata_size = device_end_address - device_start_address; } // at the ending else if ((requested_start_address + DATA_STREAM_PAGE_SIZE) > DATA_STREAM_DEVICE_END_ADDRESS) { device_start_address = DATA_STREAM_DEVICE_END_ADDRESS - DATA_STREAM_PAGE_SIZE; device_reqdata_size = device_end_address - device_start_address; device_reqdata_size = device_end_address - device_start_address; } // in the middle else { device_start_address -= extra_retdata_size_div2; device_end_address -= extra_retdata_size_div2; device_reqdata_size = device_end_address - device_start_address; } } #endif // copy from your device the data by using the previous calculations if (data_stream_load_hk != NULL) data_stream_load_hk(device_start_address, device_end_address, device_reqdata_size, page.data); page.size = device_reqdata_size; page.start_address = device_start_address - DATA_STREAM_DEVICE_START_ADDRESS; } int data_stream_get(uint32_t address, uint16_t requested_size, uint8_t* buffer) { uint32_t requested_start_address = address; uint32_t requested_end_address = address + requested_size; uint32_t page_start_address = page.start_address; uint32_t page_end_address = page.start_address + page.size; if (requested_size > DATA_STREAM_PAGE_SIZE) return -1; if (requested_size > page.size) { reload_buffer(requested_start_address, requested_size); requested_start_address = address; requested_end_address = address + requested_size; page_start_address = page.start_address; page_end_address = page.start_address + page.size; } if (requested_start_address >= page_start_address && requested_end_address <= page_end_address) { memmove(buffer, &page.data[requested_start_address - page_start_address], requested_size); return 0; } reload_buffer(requested_start_address, requested_size); requested_start_address = address; requested_end_address = address + requested_size; page_start_address = page.start_address; page_end_address = page.start_address + page.size; if (requested_start_address >= page_start_address && requested_start_address <= page_end_address) { memmove(buffer, &page.data[requested_start_address - page_start_address], requested_size); return 0; } return -1; }
// Example
#include <stdio.h> #include <string.h> #include <inttypes.h> #include "data_stream.h" uint8_t device_data[10000] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21 }; void my_loading_function(int start_address, int end_address, int size, uint8_t* buffer) { memmove(buffer, &device_data[start_address], size); } int main() { data_stream_load_hk = my_loading_function; data_stream_init(); uint8_t buffer[2]; printf("\nTest | Random Access\n"); for (int i = 0; i < 10; i++) { data_stream_get(rand()%9000, 2, buffer); printf("\n%2X %2X ", (int)buffer[0], (int)buffer[1]); } return 0; }