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

 

 

Author

Write A Comment