Home arrow Support arrow Forums

Luminary Micro Forums

dereksoftstuff

Expert Boarder

2008/11/10 06:19

HowTo : Cyclic Buffers + multi-sensor example

A library for generic Cyclic buffers.
Can be used for implementing low level FIFO buffers (BYTE) or any user data type buffers (BUFFER_ITEM). Buffer is allocated dynamically on creation, and remains at this fixed size for its duration of use.

Built upon :-

malloc

locks

If using LOCKS, can have multiple simultaneous writers to one buffer, and one reader. This is demonstrated in the example for a multi-sensor data logger.

cyclicBuffer.h & cyclicBuffer.c



Code:

  #ifndef CYCLIC_BUFFER_H_ #define CYCLIC_BUFFER_H_ #include <systemDefs.h> #include <locks.h> #ifdef __cplusplus extern "C" { #endif // ---------------------------------------------------------------------------------- // generic cyclic buffer // can be used with ANY User data type // each data item is the same size - allocate on create // data is allocated dynamically // // Default : One writer and one reader allowed simultaneously (e.g function & ISR) - separate read/ write ptrs // Multiple writers allowed depending on locks used, still with one reader // There are 2 sets of functions - based on BUFFER_ITEM and BYTE types - choose only one, don't mix // BUFFER_ITEM can be any type  //        - bufferWriteItemWithLock() is for use with multiple writers (ISRs) e.g queues // BYTE is for low level use with FIFOs ...         //     // ----------------------------------------------------------------------------------      typedef void *BUFFER_ID; typedef void *BUFFER_ITEM// user data type  (your stuff) typedef struct bufferSizeType {     UINT bufferSize;        // length of buffer   e.g. 100 32bit integers = (100, 4)     UINT itemByteSize;        // unit size     }; // ---------------------------------------------------------------------------------- #define BUFFER_ID_ERROR       0   #if defined(USE_LOCKS) // can specify the interrupt locking strategy(if any) via params - for multiple writers BUFFER_ID createBufferWithNewLock(struct bufferSizeType sizeInfostruct lockType lockInfo);  // if already have a lock to use BUFFER_ID createBufferWithLock(struct bufferSizeType sizeInfoLOCK_ID lockId);  #else BUFFER_ID createBuffer(struct bufferSizeType sizeInfo);  #endif // USE_LOCKS BUFFER_ID deleteBuffer(BUFFER_ID bufferId);  // ensure bufferId reset by return boolean cleanBuffer(BUFFER_ID bufferId);     // reset to empty boolean isBufferEmpty(BUFFER_ID bufferId); boolean isBufferFull(BUFFER_ID bufferId); // ---------------------------------------------------------------------------------- // ITEM only // ---------------------------------------------------------------------------------- UINT itemsInBuffer(BUFFER_ID bufferId); UINT freeItemsInBuffer(BUFFER_ID bufferId); void bufferWriteItem(BUFFER_ID bufferIdBUFFER_ITEM item);  #if defined(USE_LOCKS) boolean bufferWriteItemWithLock(BUFFER_ID bufferIdBUFFER_ITEM item);  #endif // USE_LOCKS void bufferReadItem(BUFFER_ID bufferIdBUFFER_ITEM item); // ---------------------------------------------------------------------------------- // BYTE only // ---------------------------------------------------------------------------------- UINT bytesInBuffer(BUFFER_ID bufferId); UINT freeBytesInBuffer(BUFFER_ID bufferId); BYTE bufferReadByte(BUFFER_ID bufferId); void bufferWriteByte(BUFFER_ID bufferIdBYTE itemByte); // for peeking and direct manipulation of bytes - use with care void startBufferPeek(BUFFER_ID bufferId);       BYTE bufferPeekByte(BUFFER_ID bufferId); void stopBufferPeek(BUFFER_ID bufferId);       #ifdef __cplusplus } #endif #endif // CYCLIC_BUFFER_H_




Code:

  #include <cyclicBuffer.h> #include <systemRAM.h>  #include <locks.h>  #include <malloc.h> #include <string.h> #include <stdlib.h> #ifdef __cplusplus extern "C" { #endif      #define MIN_BUFFER_SIZE        2 #define MIN_BUFFER_ITEM_SIZE   1  // bytes typedef BYTE *BUFFER_UNIT; typedef struct bufferInfoType {     UINT itemSize;     UINT bufferSize;     UINT totalSize;          BUFFER_UNIT readPtr;     BUFFER_UNIT writePtr;          BUFFER_UNIT bufferStart;     BUFFER_UNIT bufferEnd;     // start byte of last item     BUFFER_UNIT bufferByteEnd// last byte           BUFFER_UNIT peekStart;     BUFFER_UNIT peekPtr; #if defined(USE_LOCKS)     boolean     reuseLock;     LOCK_ID     lockId; #endif // USE_LOCKS      }; // ************************************************************* // locals // ************************************************************* BUFFER_UNIT cyclicBufferIncrement(struct bufferInfoType *bufferInfoBUFFER_UNIT ptr) {     if (ptr == bufferInfo->bufferEnd) {         ptr bufferInfo->bufferStart// wrap     } else {         ptr += bufferInfo->itemSize;         }     return ptr; } BUFFER_UNIT cyclicBufferDecrement(struct bufferInfoType *bufferInfoBUFFER_UNIT ptr) {     if (ptr == bufferInfo->bufferStart) {         ptr bufferInfo->bufferEnd// wrap     } else {         ptr -= bufferInfo->itemSize;         }     return ptr; } void resetBufferPtrs(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;          bufferInfo->readPtr bufferInfo->bufferStart;     bufferInfo->writePtr bufferInfo->bufferStart;     bufferInfo->peekStart bufferInfo->bufferStart;     bufferInfo->peekPtr bufferInfo->bufferStart; } // ************************************************************* // implementations // ************************************************************* #if defined(USE_LOCKS) BUFFER_ID createBufferWithReuseLock(struct bufferSizeType sizeInfoLOCK_ID lockIdboolean reuseLock) {      #else      BUFFER_ID createBuffer(struct bufferSizeType sizeInfo) {      #endif // USE_LOCKS              #if defined(USE_LOCKS)     lockAll(); #endif // USE_LOCKS         BUFFER_ID bufferId;          if ((sizeInfo.bufferSize >= MIN_BUFFER_SIZE) &&          (sizeInfo.itemByteSize >= MIN_BUFFER_ITEM_SIZE)) {                  bufferId malloc(sizeof(struct bufferInfoType));              if (bufferId != BUFFER_ID_ERROR) {                              struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;             UINT totalSize = (sizeInfo.bufferSize 1) * sizeInfo.itemByteSize// extra 1 for spare slot (Full check)                      bufferInfo->bufferStart = (BYTE*)malloc(totalSize);                          if (bufferInfo->bufferStart != BUFFER_ID_ERROR) {                 bufferInfo->totalSize totalSize;                 bufferInfo->bufferEnd bufferInfo->bufferStart bufferInfo->totalSize sizeInfo.itemByteSize;                 bufferInfo->bufferByteEnd bufferInfo->bufferStart bufferInfo->totalSize 1;                 bufferInfo->bufferSize sizeInfo.bufferSize// extra slot - empty/full checks                 bufferInfo->itemSize sizeInfo.itemByteSize;                  #if defined(USE_LOCKS)                                 bufferInfo->lockId lockId;                  bufferInfo->reuseLock reuseLock; #endif // USE_LOCKS                                  resetBufferPtrs(bufferId);             } else {                 bufferId freeMemory(bufferId);                         }                             }      } else {         bufferId BUFFER_ID_ERROR;     }      #if defined(USE_LOCKS)                     //tidy     if ((bufferId == BUFFER_ID_ERROR) && !reuseLock) {         lockId deleteLock(lockId);     } #endif // USE_LOCKS      #if defined(USE_LOCKS)     unLockAll(); #endif // USE_LOCKS                  return bufferId; } #if defined(USE_LOCKS) BUFFER_ID createBufferWithLock(struct bufferSizeType sizeInfoLOCK_ID lockId) {     return createBufferWithReuseLock(sizeInfolockIdTRUE); } BUFFER_ID createBufferWithNewLock(struct bufferSizeType sizeInfostruct lockType lockInfo) {          LOCK_ID lockId getLockId(lockInfo);           if (lockId == LOCK_ID_FAILED) {         return BUFFER_ID_ERROR;     }           return createBufferWithReuseLock(sizeInfolockIdFALSE); } #endif // USE_LOCKS     BUFFER_ID deleteBuffer(BUFFER_ID bufferId) {          if (validHeapAddress(bufferId)) {                  struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;              #if defined(USE_LOCKS)         lockAll(); #endif // USE_LOCKS     #if defined(USE_LOCKS)         if (!bufferInfo->reuseLock) {             bufferInfo->lockId deleteLock(bufferInfo->lockId);         } #endif // USE_LOCKS                      bufferInfo->bufferStart = (BYTE*)freeMemory(bufferInfo->bufferStart);                     bufferId freeMemory(bufferId);             #if defined(USE_LOCKS)         unLockAll(); #endif // USE_LOCKS                      }     return bufferId; } boolean cleanBuffer(BUFFER_ID bufferId) {              if (validHeapAddress(bufferId)) {                  struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;          #if defined(USE_LOCKS)         lock(bufferInfo->lockId);     #endif // USE_LOCKS                  resetBufferPtrs(bufferId);              #if defined(USE_LOCKS)         unLock(bufferInfo->lockId); #endif // USE_LOCKS              return TRUE;     }     return FALSE; } // ---------------------------------------------------------------------------- boolean isBufferEmpty(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;             return (bufferInfo->writePtr == bufferInfo->readPtr) ? TRUE FALSE;     } boolean isBufferFull(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;                 return (bytesInBuffer(bufferId) == (bufferInfo->bufferSize bufferInfo->itemSize)) ? TRUE FALSE; } // ---------------------------------------------------------------------------- UINT itemsInBuffer(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;         return bytesInBuffer(bufferId) / bufferInfo->itemSize; } UINT freeItemsInBuffer(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;     return bufferInfo->bufferSize itemsInBuffer(bufferId); } // use freeItemsInBuffer before calling - to get max number of times to call this void bufferWriteItem(BUFFER_ID bufferIdBUFFER_ITEM item) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;             memcpy(bufferInfo->writePtritembufferInfo->itemSize);         bufferInfo->writePtr cyclicBufferIncrement(bufferInfobufferInfo->writePtr);          } #if defined(USE_LOCKS) boolean bufferWriteItemWithLock(BUFFER_ID bufferIdBUFFER_ITEM item) {     boolean successStatus FALSE;          struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;             lock(bufferInfo->lockId);          if (!isBufferFull(bufferId)) {         bufferWriteItem(bufferIditem);         successStatus TRUE;     }          unLock(bufferInfo->lockId);          return successStatus; } #endif // USE_LOCKS // use itemsInBuffer before calling - to get max number of times to call this void bufferReadItem(BUFFER_ID bufferIdBUFFER_ITEM item) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;             memcpy(itembufferInfo->readPtrbufferInfo->itemSize);     bufferInfo->readPtr cyclicBufferIncrement(bufferInfobufferInfo->readPtr); } // -------------------------------------------------------------------------- // byte access modules for low-level interfacing // -------------------------------------------------------------------------- UINT bytesInBuffer(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;          if (bufferInfo->writePtr >= bufferInfo->readPtr) {         return (bufferInfo->writePtr bufferInfo->readPtr);     } else {         // wrap         return bufferInfo->totalSize - (bufferInfo->readPtr bufferInfo->writePtr);             }     } UINT freeBytesInBuffer(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;     return (bufferInfo->bufferSize bufferInfo->itemSize) - bytesInBuffer(bufferId); } // use freeBytesInBuffer before calling - to get max number of times to call this void bufferWriteByte(BUFFER_ID bufferIdBYTE itemByte) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;          *bufferInfo->writePtr itemByte;          if (bufferInfo->writePtr == bufferInfo->bufferByteEnd) {         bufferInfo->writePtr bufferInfo->bufferStart// wrap     } else {         bufferInfo->writePtr++;         } } // use bytesInBuffer before calling - to get max number of times to call this BYTE bufferReadByte(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;         BYTE itemByte = *bufferInfo->readPtr;          if (bufferInfo->readPtr == bufferInfo->bufferByteEnd) {         bufferInfo->readPtr bufferInfo->bufferStart// wrap     } else {         bufferInfo->readPtr++;         }     return itemByte; } // The peek functions are for error detection of your data on the read side of the buffer // Only use if you need to repeat process the data. // use bytesInBuffer before calling the peek functions to get the  // number of bytes in the buffer - this will determine how many times to call bufferPeekByte. // The peek functions allow access to the read side of buffer, without moving // the read ptr forwards - this allows multiple reads of the same part of the buffer  // for error detection // order of use :- // 1) startBufferPeek  // 2) bufferPeekByte - multiple calls // 3) stopBufferPeek // Note that 1) and 2) can be repeated also, before calling 3) // Calling 3) stopBufferPeek will realign the buffer read ptr - so should be used with CARE void startBufferPeek(BUFFER_ID bufferId) {         struct bufferInfoType *bufferInfo  = (struct bufferInfoType*)bufferId;     bufferInfo->peekStart bufferInfo->readPtr;     bufferInfo->peekPtr bufferInfo->peekStart; } BYTE bufferPeekByte(BUFFER_ID bufferId) {     struct bufferInfoType *bufferInfo = (struct bufferInfoType*)bufferId;         BYTE itemByte = *bufferInfo->peekPtr;          if (bufferInfo->peekPtr == bufferInfo->bufferByteEnd) {         bufferInfo->peekPtr bufferInfo->bufferStart// wrap     } else {         bufferInfo->peekPtr++;         }     return itemByte; } // use with CARE - aligning the readPtr void stopBufferPeek(BUFFER_ID bufferId) {         struct bufferInfoType *bufferInfo  = (struct bufferInfoType*)bufferId;     bufferInfo->readPtr bufferInfo->peekPtr; } #ifdef __cplusplus } #endif

login or register to reply

dereksoftstuff

Expert Boarder

2008/11/10 06:29

Re:HowTo : Cyclic Buffers + multi-sensor example

Example - multi-sensor data logger

Also uses :-

timers


Code:

  #ifndef EXAMPLE_CYCLIC_BUFFER_H_ #define EXAMPLE_CYCLIC_BUFFER_H_ #include <systemDefs.h> #ifdef __cplusplus extern "C" { #endif boolean exampleCyclicBuffer(void); #ifdef __cplusplus } #endif #endif // EXAMPLE_CYCLIC_BUFFER_H_




Code:

  #include <systemDefs.h> #include <timerUtils.h> #include <cyclicBuffer.h> #include <exampleCyclicBuffer.h> #include <display.h>  #include <hw_ints.h> #include <interrupt.h> #include <sysctl.h> #include <lmi_timer.h> // maybe called timer.h #include <stdlib.h>    // rand #ifdef __cplusplus extern "C" { #endif      // Interrupt frequency - simulate new sensor reading available #define SENSOR_SIMULATOR_usTIME_PERIOD    100      #define SENSOR_BUFFER_SIZE       100            // num items buffer can hold  #define SENSOR_BUFFER_UNIT_SIZE  sizeof(UINT)   // each item byte size static BUFFER_ID sensorBuffer; typedef struct sensorInfoType {     UINT value;     UINT numReadings;     UINT numMissedReadings; }; static struct sensorInfoType sensor1; static struct sensorInfoType sensor2; #if defined(USE_LOCKS) #if defined(USE_LOCK_GROUP)    static BYTE interruptIds[3] = { INT_TIMER2AINT_TIMER3ANULL };  #endif // USE_LOCK_GROUP #endif // USE_LOCKS // ------------------------------------------------------------------------- void Timer2IntHandler(void) {          // Clear the timer interrupt.     TimerIntClear(TIMER2_BASETIMER_TIMA_TIMEOUT);            sensor1.value rand() % 100000;  // simulate sensor readings            #if defined(USE_LOCKS)          //------------------------------------------     // test multiwriters     //------------------------------------------               if (bufferWriteItemWithLock(sensorBuffer, &sensor1.value)) {         sensor1.numReadings++;     } else {         sensor1.numMissedReadings++;     } #else     // single writer     if (!isBufferFull(sensorBuffer)) {         bufferWriteItem(sensorBuffer, &sensor1.value);         sensor1.numReadings++;     } else {         sensor1.numMissedReadings++;     } #endif // USE_LOCKS } void Timer3IntHandler(void) {          // Clear the timer interrupt.     TimerIntClear(TIMER3_BASETIMER_TIMA_TIMEOUT);                #if defined(USE_LOCKS)              //------------------------------------------     // test multiwriters     //------------------------------------------          sensor2.value rand() % 100;  // simulate sensor readings     if (bufferWriteItemWithLock(sensorBuffer, &sensor2.value)) {         sensor2.numReadings++;     } else {         sensor2.numMissedReadings++;     } #endif // USE_LOCKS      } // ------------------------------------------------------------------------- boolean initSensorSimulator(UINT bufferSizeUINT usTimePeriod) {         // ------------------------------------------------------        // writer 1      // ------------------------------------------------------        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);     // Configure 32-bit periodic timer     TimerConfigure(TIMER2_BASETIMER_CFG_32_BIT_PER);        TimerLoadSet(TIMER2_BASETIMER_AusTimePeriod NUM_CLOCKS_IN_MICROSEC);        TimerIntEnable(TIMER2_BASETIMER_TIMA_TIMEOUT);     TimerEnable(TIMER2_BASETIMER_A);           // ------------------------------------------------------        // writer 2      // ------------------------------------------------------     SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);     // Configure 32-bit periodic timer     TimerConfigure(TIMER3_BASETIMER_CFG_32_BIT_PER);        TimerLoadSet(TIMER3_BASETIMER_A, ((usTimePeriod 2) - 1) * NUM_CLOCKS_IN_MICROSEC);      TimerIntEnable(TIMER3_BASETIMER_TIMA_TIMEOUT);     TimerEnable(TIMER3_BASETIMER_A);            // ------------------------------------------------------          struct bufferSizeType sizeInfo;        sizeInfo.bufferSize bufferSize;     sizeInfo.itemByteSize SENSOR_BUFFER_UNIT_SIZE;   #if defined(USE_LOCKS)          struct lockType lockInfo;           // ***************************  try each of these ********************************** //    lockInfo.lockClass = NO_LOCKS;     lockInfo.lockClass LOCKS; // *********************************************************************************                         #if defined(USE_LOCK_ALL)     // 2A higher priority than 3A     IntPrioritySet(INT_TIMER2A0x80);     IntPrioritySet(INT_TIMER3A0xC0);          #elif defined(USE_LOCK_GROUP)          lockInfo.interruptIds interruptIds;          // 2A higher priority than 3A     IntPrioritySet(INT_TIMER2A0x80);     IntPrioritySet(INT_TIMER3A0xC0);          #elif defined(USE_LOCK_PRIORITY)              setInterruptPriorityLevel(INT_TIMER2A4);     setInterruptPriorityLevel(INT_TIMER3A4);          lockInfo.priorityMask 4// for thread #endif // LOCK TYPE         sensorBuffer createBufferWithNewLock(sizeInfolockInfo);      #else        sensorBuffer createBuffer(sizeInfo); #endif // USE_LOCKS                   if (sensorBuffer == BUFFER_ID_ERROR) {         return FALSE// error     }                     IntEnable(INT_TIMER2A);  // go     IntEnable(INT_TIMER3A);  // go         // seed random sensor input simulator     srand(TimerValueGet(TIMER0_BASETIMER_A));           return TRUE; } // ------------------------------------------------------------------------- boolean exampleCyclicBuffer(void) {          UINT numItems 0;     UINT sensorValue;     UINT i;     UINT numSensorReadingsReceived 0;     if (!initSensorSimulator(SENSOR_BUFFER_SIZESENSOR_SIMULATOR_usTIME_PERIOD)) {         return FALSE;     }                  while (TRUE) {                  numItems itemsInBuffer(sensorBuffer);         numSensorReadingsReceived += numItems;                              for (0numItemsi++) {             bufferReadItem(sensorBuffer, &sensorValue);                          // use sensorValue ...                      // loop                  // test results - prints (OLED) take a long time - disable interrupts while printing #if defined(USE_LOCKS)          #if defined(USE_LOCK_ALL)         lockAll(); #elif defined(USE_LOCK_GROUP)         lockGroup(interruptIds); #elif defined(USE_LOCK_PRIORITY)         lockPriority(4); #endif // LOCK TYPE                                       // sensor results         // ------------------         UINT line 0;                  printValue(numItems80line);                           // this value should be zero - or close to zero allowing for buffered data         // if this value starts growing then writers are interfering with each other - ERROR  (NO_LOCKS)         // using LOCKS will cure this error         printValue((sensor1.numReadings sensor2.numReadings) - numSensorReadingsReceived0line);          line += 10;         printValue(sensor1.numReadings0line);          printValue(sensor1.numMissedReadings60line);                   line += 10;       &n