https://github.com/jwhiddon/EDB
/*
EDB.cpp
Extended Database Library for Arduino
http://www.arduino.cc/playground/Code/ExtendedDatabaseLibrary
*/
// Thanks to robtillaar (http://forum.arduino.cc/index.php/topic,130228.0.html) for the next line...
#include "Arduino.h"
#include "EDB.h"
/**************************************************/
// private functions
// low level byte write
void EDB::edbWrite(unsigned long ee, const byte* p, unsigned int recsize)
{ if(!_write_buffer){
for (unsigned int i = 0; i < recsize; i++)
_write_byte(ee++, *p++);
}else{
_write_buffer(ee,p,recsize);
}
}
// low level byte read
void EDB::edbRead(unsigned long ee, byte* p, unsigned int recsize)
{ if(!_read_buffer){
for (unsigned i = 0; i < recsize; i++)
*p++ = _read_byte(ee++);
}else{
_read_buffer(ee,p,recsize);
}
}
// writes EDB_Header
void EDB::writeHead()
{
edbWrite(EDB_head_ptr, EDB_REC EDB_head, (unsigned long)sizeof(EDB_Header));
}
// reads EDB_Header
void EDB::readHead()
{
edbRead(EDB_head_ptr, EDB_REC EDB_head, (unsigned long)sizeof(EDB_Header));
}
/**************************************************/
// public functions
EDB::EDB(EDB_Write_Handler *w, EDB_Read_Handler *r)
{
_write_byte = w;
_read_byte = r;
_write_buffer = NULL;
_read_buffer = NULL;
}
EDB::EDB(EDB_Write_Buffer *w, EDB_Read_Buffer *r)
{
_write_byte = NULL;
_read_byte = NULL;
_write_buffer = w;
_read_buffer = r;
}
// creates a new table and sets header values
EDB_Status EDB::create(unsigned long head_ptr, unsigned long tablesize, unsigned int recsize)
{
EDB_head_ptr = head_ptr;
EDB_table_ptr = sizeof(EDB_Header) + EDB_head_ptr;
EDB_head.flag = EDB_FLAG;
EDB_head.n_recs = 0;
EDB_head.rec_size = recsize;
EDB_head.table_size = tablesize;
writeHead();
if (EDB_head.flag == EDB_FLAG){
return EDB_OK;
} else {
return EDB_ERROR;
}
}
// reads an existing edb header at a given recno and sets header values
EDB_Status EDB::open(unsigned long head_ptr)
{
EDB_head_ptr = head_ptr;
// Thanks to Steve Kelly for the next line...
EDB_table_ptr = sizeof(EDB_Header) + EDB_head_ptr; // this line was originally missing in the downloaded library
readHead();
return EDB_OK;
}
// writes a record to a given recno
EDB_Status EDB::writeRec(unsigned long recno, const EDB_Rec rec)
{
edbWrite(EDB_table_ptr + ((recno - 1) * EDB_head.rec_size), rec, EDB_head.rec_size);
return EDB_OK;
}
// reads a record from a given recno
EDB_Status EDB::readRec(unsigned long recno, EDB_Rec rec)
{
if (recno < 1 || recno > EDB_head.n_recs) return EDB_OUT_OF_RANGE;
edbRead(EDB_table_ptr + ((recno - 1) * EDB_head.rec_size), rec, EDB_head.rec_size);
return EDB_OK;
}
// Deletes a record at a given recno
// Becomes more inefficient as you the record set increases and you delete records
// early in the record queue.
EDB_Status EDB::deleteRec(unsigned long recno)
{
if (recno < 0 || recno > EDB_head.n_recs) return EDB_OUT_OF_RANGE;
EDB_Rec rec = (byte*)malloc(EDB_head.rec_size);
for (unsigned long i = recno + 1; i <= EDB_head.n_recs; i++)
{
readRec(i, rec);
writeRec(i - 1, rec);
}
free(rec);
EDB_head.n_recs--;
writeHead();
return EDB_OK;
}
// Inserts a record at a given recno, increasing all following records' recno by 1.
// This function becomes increasingly inefficient as it's currently implemented and
// is the slowest way to add a record.
EDB_Status EDB::insertRec(unsigned long recno, EDB_Rec rec)
{
if (count() == limit()) return EDB_TABLE_FULL;
if (count() > 0 && (recno < 0 || recno > EDB_head.n_recs)) return EDB_OUT_OF_RANGE;
if (count() == 0 && recno == 1) return appendRec(rec);
EDB_Rec buf = (byte*)malloc(EDB_head.rec_size);
for (unsigned long i = EDB_head.n_recs; i >= recno; i--)
{
readRec(i, buf);
writeRec(i + 1, buf);
}
free(buf);
writeRec(recno, rec);
EDB_head.n_recs++;
writeHead();
return EDB_OK;
}
// Updates a record at a given recno
EDB_Status EDB::updateRec(unsigned long recno, EDB_Rec rec)
{
if (recno < 0 || recno > EDB_head.n_recs) return EDB_OUT_OF_RANGE;
writeRec(recno, rec);
return EDB_OK;
}
// Adds a record to the end of the record set.
// This is the fastest way to add a record.
EDB_Status EDB::appendRec(EDB_Rec rec)
{
if (EDB_head.n_recs + 1 > limit()) return EDB_TABLE_FULL;
EDB_head.n_recs++;
writeRec(EDB_head.n_recs,rec);
writeHead();
return EDB_OK;
}
// returns the number of queued items
unsigned long EDB::count()
{
return EDB_head.n_recs;
}
// returns the maximum number of items that will fit into the queue
unsigned long EDB::limit()
{
// Thanks to [email protected] for the next line
return (EDB_head.table_size - sizeof(EDB_Header)) / EDB_head.rec_size;
}
// truncates the queue by resetting the internal pointers
void EDB::clear()
{
readHead();
create(EDB_head_ptr, EDB_head.table_size, EDB_head.rec_size);
}
/*
EDB.h
Extended Database Library for Arduino
http://www.arduino.cc/playground/Code/ExtendedDatabaseLibrary
*/
#ifndef EDB_PROM
#define EDB_PROM
#define EDB_FLAG B11011011
struct EDB_Header
{
byte flag;
unsigned long n_recs;
unsigned int rec_size;
unsigned long table_size;
};
enum EDB_Status {
EDB_OK,
EDB_ERROR,
EDB_OUT_OF_RANGE,
EDB_TABLE_FULL
};
typedef byte* EDB_Rec;
#define EDB_REC (byte*)(void*)&
class EDB {
public:
typedef void EDB_Write_Handler(unsigned long, const uint8_t);
typedef uint8_t EDB_Read_Handler(unsigned long);
typedef void EDB_Write_Buffer(unsigned long, const byte*, unsigned int);
typedef void EDB_Read_Buffer(unsigned long, byte*, unsigned int);
EDB(EDB_Write_Handler *, EDB_Read_Handler *);
EDB(EDB_Write_Buffer *, EDB_Read_Buffer *);
EDB_Status create(unsigned long, unsigned long, unsigned int);
EDB_Status open(unsigned long);
EDB_Status readRec(unsigned long, EDB_Rec);
EDB_Status deleteRec(unsigned long);
EDB_Status insertRec(unsigned long, const EDB_Rec);
EDB_Status updateRec(unsigned long, const EDB_Rec);
EDB_Status appendRec(EDB_Rec rec);
unsigned long limit();
unsigned long count();
void clear();
private:
unsigned long EDB_head_ptr;
unsigned long EDB_table_ptr;
EDB_Write_Handler *_write_byte;
EDB_Read_Handler *_read_byte;
EDB_Write_Buffer *_write_buffer;
EDB_Read_Buffer *_read_buffer;
EDB_Header EDB_head;
void edbWrite(unsigned long ee, const byte* p, unsigned int);
void edbRead(unsigned long ee, byte* p, unsigned int);
void writeHead();
void readHead();
EDB_Status writeRec(unsigned long, const EDB_Rec);
};
extern EDB edb;
#endif