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;
}






