blob: 2b10c375f3e61a0fd79998a394f7d8c3319c2e92 [file] [log] [blame]
/****************************************************************************
(c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
www.systec-electronic.com
Project: Project independend shared buffer (linear + circular)
Description: Implementation of platform independend part for the
shared buffer
License:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SYSTEC electronic GmbH nor the names of its
contributors may be used to endorse or promote products derived
from this software without prior written permission. For written
permission, please contact info@systec-electronic.com.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Severability Clause:
If a provision of this License is or becomes illegal, invalid or
unenforceable in any jurisdiction, that shall not affect:
1. the validity or enforceability in that jurisdiction of any other
provision of this License; or
2. the validity or enforceability in other jurisdictions of that or
any other provision of this License.
-------------------------------------------------------------------------
2006/06/27 -rs: V 1.00 (initial version)
****************************************************************************/
#if defined(WIN32) || defined(_WIN32)
#ifdef UNDER_RTSS
// RTX header
#include <windows.h>
#include <process.h>
#include <rtapi.h>
#elif __BORLANDC__
// borland C header
#include <windows.h>
#include <process.h>
#elif WINCE
#include <windows.h>
#else
// MSVC needs to include windows.h at first
// the following defines ar necessary for function prototypes for waitable timers
#define _WIN32_WINDOWS 0x0401
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <process.h>
#endif
#endif
#include "global.h"
#include "SharedBuff.h"
#include "ShbIpc.h"
#include <linux/string.h>
#include <linux/kernel.h>
/***************************************************************************/
/* */
/* */
/* G L O B A L D E F I N I T I O N S */
/* */
/* */
/***************************************************************************/
//---------------------------------------------------------------------------
// Configuration
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Constant definitions
//---------------------------------------------------------------------------
#define SBC_MAGIC_ID 0x53424323 // magic ID ("SBC#")
#define SBL_MAGIC_ID 0x53424C23 // magic ID ("SBL#")
//---------------------------------------------------------------------------
// Local types
//---------------------------------------------------------------------------
// structure to administrate circular shared buffer head
typedef struct {
unsigned long m_ShbCirMagicID; // magic ID ("SBC#")
unsigned long m_ulBufferTotalSize; // over-all size of complete buffer
unsigned long m_ulBufferDataSize; // size of complete data area
unsigned long m_ulWrIndex; // current write index (set bevore write)
unsigned long m_ulRdIndex; // current read index (set after read)
unsigned long m_ulNumOfWriteJobs; // number of currently (parallel running) write operations
unsigned long m_ulDataInUse; // currently used buffer size (incl. uncompleted write operations)
unsigned long m_ulDataApended; // buffer size of complete new written but not yet readable data (in case of m_ulNumOfWriteJobs>1)
unsigned long m_ulBlocksApended; // number of complete new written but not yet readable data blocks (in case of m_ulNumOfWriteJobs>1)
unsigned long m_ulDataReadable; // buffer size with readable (complete written) data
unsigned long m_ulBlocksReadable; // number of readable (complete written) data blocks
tShbCirSigHndlrNewData m_pfnSigHndlrNewData; // application handler to signal new data
unsigned int m_fBufferLocked; // TRUE if buffer is locked (because of pending reset request)
tShbCirSigHndlrReset m_pfnSigHndlrReset; // application handler to signal buffer reset is done
unsigned char m_Data; // start of data area (the real data size is unknown at this time)
} tShbCirBuff;
// structure to administrate linear shared buffer head
typedef struct {
unsigned int m_ShbLinMagicID; // magic ID ("SBL#")
unsigned long m_ulBufferTotalSize; // over-all size of complete buffer
unsigned long m_ulBufferDataSize; // size of complete data area
unsigned char m_Data; // start of data area (the real data size is unknown at this time)
} tShbLinBuff;
// type to save size of a single data block inside the circular shared buffer
typedef struct {
unsigned int m_uiFullBlockSize:28; // a single block must not exceed a length of 256MByte :-)
unsigned int m_uiAlignFillBytes:4;
} tShbCirBlockSize;
#define SBC_BLOCK_ALIGNMENT 4 // alignment must *not* be lower than sizeof(tShbCirBlockSize)!
#define SBC_MAX_BLOCK_SIZE ((1<<28)-1) // = (2^28 - 1) = (256MByte - 1) -> should be enought for real life :-)
#define SBL_BLOCK_ALIGNMENT 4
#define SBL_MAX_BLOCK_SIZE ((1<<28)-1) // = (2^28 - 1) = (256MByte - 1) -> should be enought for real life :-)
//---------------------------------------------------------------------------
// Global variables
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Local variables
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Prototypes of internal functions
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Get pointer to Circular Shared Buffer
//---------------------------------------------------------------------------
tShbCirBuff *ShbCirGetBuffer(tShbInstance pShbInstance_p)
{
tShbCirBuff *pShbCirBuff;
pShbCirBuff = (tShbCirBuff *) ShbIpcGetShMemPtr(pShbInstance_p);
ASSERT(pShbCirBuff->m_ShbCirMagicID == SBC_MAGIC_ID);
return (pShbCirBuff);
}
//---------------------------------------------------------------------------
// Get pointer to Linear Shared Buffer
//---------------------------------------------------------------------------
tShbLinBuff *ShbLinGetBuffer(tShbInstance pShbInstance_p)
{
tShbLinBuff *pShbLinBuff;
pShbLinBuff = (tShbLinBuff *) ShbIpcGetShMemPtr(pShbInstance_p);
ASSERT(pShbLinBuff->m_ShbLinMagicID == SBL_MAGIC_ID);
return (pShbLinBuff);
}
// not inlined internal functions
int ShbCirSignalHandlerNewData(tShbInstance pShbInstance_p);
void ShbCirSignalHandlerReset(tShbInstance pShbInstance_p,
unsigned int fTimeOut_p);
//=========================================================================//
// //
// P U B L I C F U N C T I O N S //
// //
//=========================================================================//
// not inlined external functions
//---------------------------------------------------------------------------
// Initialize Shared Buffer Module
//---------------------------------------------------------------------------
tShbError ShbInit(void)
{
tShbError ShbError;
ShbError = ShbIpcInit();
return (ShbError);
}
//---------------------------------------------------------------------------
// Deinitialize Shared Buffer Module
//---------------------------------------------------------------------------
tShbError ShbExit(void)
{
tShbError ShbError;
ShbError = ShbIpcExit();
return (ShbError);
}
//-------------------------------------------------------------------------//
// //
// C i r c u l a r S h a r e d B u f f e r //
// //
//-------------------------------------------------------------------------//
//---------------------------------------------------------------------------
// Allocate Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirAllocBuffer(unsigned long ulBufferSize_p,
const char *pszBufferID_p,
tShbInstance * ppShbInstance_p,
unsigned int *pfShbNewCreated_p)
{
tShbInstance pShbInstance;
tShbCirBuff *pShbCirBuff;
unsigned int fShbNewCreated;
unsigned long ulBufferDataSize;
unsigned long ulBufferTotalSize;
tShbError ShbError;
// check arguments
if ((ulBufferSize_p == 0) || (ppShbInstance_p == NULL)) {
return (kShbInvalidArg);
}
// calculate length of memory to allocate
ulBufferDataSize =
(ulBufferSize_p +
(SBC_BLOCK_ALIGNMENT - 1)) & ~(SBC_BLOCK_ALIGNMENT - 1);
ulBufferTotalSize = ulBufferDataSize + sizeof(tShbCirBuff);
// allocate a new or open an existing shared buffer
ShbError = ShbIpcAllocBuffer(ulBufferTotalSize, pszBufferID_p,
&pShbInstance, &fShbNewCreated);
if (ShbError != kShbOk) {
goto Exit;
}
if (pShbInstance == NULL) {
ShbError = kShbOutOfMem;
goto Exit;
}
// get pointer to shared buffer
pShbCirBuff = (tShbCirBuff *) ShbIpcGetShMemPtr(pShbInstance);
// if the shared buffer was new created, than this process has
// to initialize it, otherwise the buffer is already in use
// and *must not* be reseted
if (fShbNewCreated) {
#ifndef NDEBUG
{
memset(pShbCirBuff, 0xCC, ulBufferTotalSize);
}
#endif
pShbCirBuff->m_ShbCirMagicID = SBC_MAGIC_ID;
pShbCirBuff->m_ulBufferTotalSize = ulBufferTotalSize;
pShbCirBuff->m_ulBufferDataSize = ulBufferDataSize;
pShbCirBuff->m_ulWrIndex = 0;
pShbCirBuff->m_ulRdIndex = 0;
pShbCirBuff->m_ulNumOfWriteJobs = 0;
pShbCirBuff->m_ulDataInUse = 0;
pShbCirBuff->m_ulDataApended = 0;
pShbCirBuff->m_ulBlocksApended = 0;
pShbCirBuff->m_ulDataReadable = 0;
pShbCirBuff->m_ulBlocksReadable = 0;
pShbCirBuff->m_pfnSigHndlrNewData = NULL;
pShbCirBuff->m_fBufferLocked = FALSE;
pShbCirBuff->m_pfnSigHndlrReset = NULL;
} else {
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
}
Exit:
*ppShbInstance_p = pShbInstance;
*pfShbNewCreated_p = fShbNewCreated;
return (ShbError);
}
//---------------------------------------------------------------------------
// Release Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirReleaseBuffer(tShbInstance pShbInstance_p)
{
tShbError ShbError;
// check arguments
if (pShbInstance_p == NULL) {
ShbError = kShbOk;
goto Exit;
}
ShbError = ShbIpcReleaseBuffer(pShbInstance_p);
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Reset Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirResetBuffer(tShbInstance pShbInstance_p,
unsigned long ulTimeOut_p,
tShbCirSigHndlrReset pfnSignalHandlerReset_p)
{
tShbCirBuff *pShbCirBuff;
unsigned long ulNumOfWriteJobs = 0; // d.k. GCC complains about uninitialized variable otherwise
tShbError ShbError;
// check arguments
if (pShbInstance_p == NULL) {
ShbError = kShbInvalidArg;
goto Exit;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
// start reset job by setting request request in buffer header
ShbIpcEnterAtomicSection(pShbInstance_p);
{
if (!pShbCirBuff->m_fBufferLocked) {
ulNumOfWriteJobs = pShbCirBuff->m_ulNumOfWriteJobs;
pShbCirBuff->m_fBufferLocked = TRUE;
pShbCirBuff->m_pfnSigHndlrReset =
pfnSignalHandlerReset_p;
} else {
ShbError = kShbAlreadyReseting;
}
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
if (ShbError != kShbOk) {
goto Exit;
}
// if there is currently no running write operation then reset buffer
// immediately, otherwise wait until the last write job is ready by
// starting a signal process
if (ulNumOfWriteJobs == 0) {
// there is currently no running write operation
// -> reset buffer immediately
ShbCirSignalHandlerReset(pShbInstance_p, FALSE);
ShbError = kShbOk;
} else {
// there is currently at least one running write operation
// -> starting signal process to wait until the last write job is ready
ShbError =
ShbIpcStartSignalingJobReady(pShbInstance_p, ulTimeOut_p,
ShbCirSignalHandlerReset);
}
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Write data block to Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirWriteDataBlock(tShbInstance pShbInstance_p,
const void *pSrcDataBlock_p,
unsigned long ulDataBlockSize_p)
{
tShbCirBuff *pShbCirBuff;
tShbCirBlockSize ShbCirBlockSize;
unsigned int uiFullBlockSize;
unsigned int uiAlignFillBytes;
unsigned char *pShbCirDataPtr;
unsigned char *pScrDataPtr;
unsigned long ulDataSize;
unsigned long ulChunkSize;
unsigned long ulWrIndex = 0; // d.k. GCC complains about uninitialized variable otherwise
unsigned int fSignalNewData;
unsigned int fSignalReset;
tShbError ShbError;
tShbError ShbError2;
int fRes;
// check arguments
if (pShbInstance_p == NULL) {
ShbError = kShbInvalidArg;
goto Exit;
}
if ((pSrcDataBlock_p == NULL) || (ulDataBlockSize_p == 0)) {
// nothing to do here
ShbError = kShbOk;
goto Exit;
}
if (ulDataBlockSize_p > SBC_MAX_BLOCK_SIZE) {
ShbError = kShbExceedDataSizeLimit;
goto Exit;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
pScrDataPtr = (unsigned char *)pSrcDataBlock_p;
fSignalNewData = FALSE;
fSignalReset = FALSE;
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
// calculate data block size in circular buffer
ulDataSize =
(ulDataBlockSize_p +
(SBC_BLOCK_ALIGNMENT - 1)) & ~(SBC_BLOCK_ALIGNMENT - 1);
uiFullBlockSize = ulDataSize + sizeof(tShbCirBlockSize); // data size + header
uiAlignFillBytes = ulDataSize - ulDataBlockSize_p;
ShbCirBlockSize.m_uiFullBlockSize = uiFullBlockSize;
ShbCirBlockSize.m_uiAlignFillBytes = uiAlignFillBytes;
// reserve the needed memory for the write operation to do now
// and make necessary adjustments in the circular buffer header
ShbIpcEnterAtomicSection(pShbInstance_p);
{
// check if there is sufficient memory available to store
// the new data
fRes =
uiFullBlockSize <=
(pShbCirBuff->m_ulBufferDataSize -
pShbCirBuff->m_ulDataInUse);
if (fRes) {
// set write pointer for the write operation to do now
// to the current write pointer of the circular buffer
ulWrIndex = pShbCirBuff->m_ulWrIndex;
// reserve the needed memory for the write operation to do now
pShbCirBuff->m_ulDataInUse += uiFullBlockSize;
// set new write pointer behind the reserved memory
// for the write operation to do now
pShbCirBuff->m_ulWrIndex += uiFullBlockSize;
pShbCirBuff->m_ulWrIndex %=
pShbCirBuff->m_ulBufferDataSize;
// increment number of currently (parallel running)
// write operations
pShbCirBuff->m_ulNumOfWriteJobs++;
}
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
if (!fRes) {
ShbError = kShbBufferFull;
goto Exit;
}
// copy the data to the circular buffer
// (the copy process itself will be done outside of any
// critical/locked section)
pShbCirDataPtr = &pShbCirBuff->m_Data; // ptr to start of data area
// write real size of current block (incl. alignment fill bytes)
*(tShbCirBlockSize *) (pShbCirDataPtr + ulWrIndex) = ShbCirBlockSize;
ulWrIndex += sizeof(tShbCirBlockSize);
ulWrIndex %= pShbCirBuff->m_ulBufferDataSize;
if (ulWrIndex + ulDataBlockSize_p <= pShbCirBuff->m_ulBufferDataSize) {
// linear write operation
memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr,
ulDataBlockSize_p);
} else {
// wrap-around write operation
ulChunkSize = pShbCirBuff->m_ulBufferDataSize - ulWrIndex;
memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr, ulChunkSize);
memcpy(pShbCirDataPtr, pScrDataPtr + ulChunkSize,
ulDataBlockSize_p - ulChunkSize);
}
// adjust header information for circular buffer with properties
// of the wiritten data block
ShbIpcEnterAtomicSection(pShbInstance_p);
{
pShbCirBuff->m_ulDataApended += uiFullBlockSize;
pShbCirBuff->m_ulBlocksApended++;
// decrement number of currently (parallel running) write operations
if (!--pShbCirBuff->m_ulNumOfWriteJobs) {
// if there is no other write process running then
// set new size of readable (complete written) data and
// adjust number of readable blocks
pShbCirBuff->m_ulDataReadable +=
pShbCirBuff->m_ulDataApended;
pShbCirBuff->m_ulBlocksReadable +=
pShbCirBuff->m_ulBlocksApended;
pShbCirBuff->m_ulDataApended = 0;
pShbCirBuff->m_ulBlocksApended = 0;
fSignalNewData = TRUE;
fSignalReset = pShbCirBuff->m_fBufferLocked;
}
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
// signal new data event to a potentially reading application
if (fSignalNewData) {
ShbError2 = ShbIpcSignalNewData(pShbInstance_p);
if (ShbError == kShbOk) {
ShbError = ShbError2;
}
}
// signal that the last write job has been finished to allow
// a waiting application to reset the buffer now
if (fSignalReset) {
ShbError2 = ShbIpcSignalJobReady(pShbInstance_p);
if (ShbError == kShbOk) {
ShbError = ShbError2;
}
}
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Allocate block within the Circular Shared Buffer for chunk writing
//---------------------------------------------------------------------------
tShbError ShbCirAllocDataBlock(tShbInstance pShbInstance_p,
tShbCirChunk * pShbCirChunk_p,
unsigned long ulDataBufferSize_p)
{
tShbCirBuff *pShbCirBuff;
tShbCirBlockSize ShbCirBlockSize;
unsigned int uiFullBlockSize;
unsigned int uiAlignFillBytes;
unsigned char *pShbCirDataPtr;
unsigned long ulDataSize;
unsigned long ulWrIndex = 0; // d.k. GCC complains about uninitialized variable otherwise
tShbError ShbError;
int fRes;
// check arguments
if ((pShbInstance_p == NULL) || (pShbCirChunk_p == NULL)) {
ShbError = kShbInvalidArg;
goto Exit;
}
if (ulDataBufferSize_p == 0) {
ShbError = kShbInvalidArg;
goto Exit;
}
if (ulDataBufferSize_p > SBC_MAX_BLOCK_SIZE) {
ShbError = kShbExceedDataSizeLimit;
goto Exit;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
// calculate data block size in circular buffer
ulDataSize =
(ulDataBufferSize_p +
(SBC_BLOCK_ALIGNMENT - 1)) & ~(SBC_BLOCK_ALIGNMENT - 1);
uiFullBlockSize = ulDataSize + sizeof(tShbCirBlockSize); // data size + header
uiAlignFillBytes = ulDataSize - ulDataBufferSize_p;
ShbCirBlockSize.m_uiFullBlockSize = uiFullBlockSize;
ShbCirBlockSize.m_uiAlignFillBytes = uiAlignFillBytes;
// reserve the needed memory for the write operation to do now
// and make necessary adjustments in the circular buffer header
ShbIpcEnterAtomicSection(pShbInstance_p);
{
// check if there is sufficient memory available to store
// the new data
fRes =
(uiFullBlockSize <=
(pShbCirBuff->m_ulBufferDataSize -
pShbCirBuff->m_ulDataInUse));
if (fRes) {
// set write pointer for the write operation to do now
// to the current write pointer of the circular buffer
ulWrIndex = pShbCirBuff->m_ulWrIndex;
// reserve the needed memory for the write operation to do now
pShbCirBuff->m_ulDataInUse += uiFullBlockSize;
// set new write pointer behind the reserved memory
// for the write operation to do now
pShbCirBuff->m_ulWrIndex += uiFullBlockSize;
pShbCirBuff->m_ulWrIndex %=
pShbCirBuff->m_ulBufferDataSize;
// increment number of currently (parallel running)
// write operations
pShbCirBuff->m_ulNumOfWriteJobs++;
}
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
if (!fRes) {
ShbError = kShbBufferFull;
goto Exit;
}
// setup header information for allocated buffer
pShbCirDataPtr = &pShbCirBuff->m_Data; // ptr to start of data area
// write real size of current block (incl. alignment fill bytes)
*(tShbCirBlockSize *) (pShbCirDataPtr + ulWrIndex) = ShbCirBlockSize;
ulWrIndex += sizeof(tShbCirBlockSize);
ulWrIndex %= pShbCirBuff->m_ulBufferDataSize;
// setup chunk descriptor
pShbCirChunk_p->m_uiFullBlockSize = uiFullBlockSize;
pShbCirChunk_p->m_ulAvailableSize = ulDataBufferSize_p;
pShbCirChunk_p->m_ulWrIndex = ulWrIndex;
pShbCirChunk_p->m_fBufferCompleted = FALSE;
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Write data chunk into an allocated buffer of the Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirWriteDataChunk(tShbInstance pShbInstance_p,
tShbCirChunk *pShbCirChunk_p,
const void *pSrcDataChunk_p,
unsigned long ulDataChunkSize_p,
unsigned int *pfBufferCompleted_p)
{
tShbCirBuff *pShbCirBuff;
unsigned char *pShbCirDataPtr;
unsigned char *pScrDataPtr;
unsigned long ulSubChunkSize;
unsigned long ulWrIndex;
unsigned int fBufferCompleted;
unsigned int fSignalNewData;
unsigned int fSignalReset;
tShbError ShbError;
tShbError ShbError2;
// check arguments
if ((pShbInstance_p == NULL) || (pShbCirChunk_p == NULL)
|| (pfBufferCompleted_p == NULL)) {
ShbError = kShbInvalidArg;
goto Exit;
}
if ((pSrcDataChunk_p == NULL) || (ulDataChunkSize_p == 0)) {
// nothing to do here
ShbError = kShbOk;
goto Exit;
}
if (pShbCirChunk_p->m_fBufferCompleted) {
ShbError = kShbBufferAlreadyCompleted;
goto Exit;
}
if (ulDataChunkSize_p > pShbCirChunk_p->m_ulAvailableSize) {
ShbError = kShbExceedDataSizeLimit;
goto Exit;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
pScrDataPtr = (unsigned char *)pSrcDataChunk_p;
fSignalNewData = FALSE;
fSignalReset = FALSE;
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
ulWrIndex = pShbCirChunk_p->m_ulWrIndex;
// copy the data to the circular buffer
// (the copy process itself will be done outside of any
// critical/locked section)
pShbCirDataPtr = &pShbCirBuff->m_Data; // ptr to start of data area
if (ulWrIndex + ulDataChunkSize_p <= pShbCirBuff->m_ulBufferDataSize) {
// linear write operation
memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr,
ulDataChunkSize_p);
} else {
// wrap-around write operation
ulSubChunkSize = pShbCirBuff->m_ulBufferDataSize - ulWrIndex;
memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr, ulSubChunkSize);
memcpy(pShbCirDataPtr, pScrDataPtr + ulSubChunkSize,
ulDataChunkSize_p - ulSubChunkSize);
}
// adjust chunk descriptor
ulWrIndex += ulDataChunkSize_p;
ulWrIndex %= pShbCirBuff->m_ulBufferDataSize;
pShbCirChunk_p->m_ulAvailableSize -= ulDataChunkSize_p;
pShbCirChunk_p->m_ulWrIndex = ulWrIndex;
fBufferCompleted = (pShbCirChunk_p->m_ulAvailableSize == 0);
pShbCirChunk_p->m_fBufferCompleted = fBufferCompleted;
// if the complete allocated buffer is filled with data then
// adjust header information for circular buffer with properties
// of the wiritten data block
if (fBufferCompleted) {
ShbIpcEnterAtomicSection(pShbInstance_p);
{
pShbCirBuff->m_ulDataApended +=
pShbCirChunk_p->m_uiFullBlockSize;
pShbCirBuff->m_ulBlocksApended++;
// decrement number of currently (parallel running) write operations
if (!--pShbCirBuff->m_ulNumOfWriteJobs) {
// if there is no other write process running then
// set new size of readable (complete written) data and
// adjust number of readable blocks
pShbCirBuff->m_ulDataReadable +=
pShbCirBuff->m_ulDataApended;
pShbCirBuff->m_ulBlocksReadable +=
pShbCirBuff->m_ulBlocksApended;
pShbCirBuff->m_ulDataApended = 0;
pShbCirBuff->m_ulBlocksApended = 0;
fSignalNewData = TRUE;
fSignalReset = pShbCirBuff->m_fBufferLocked;
}
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
}
// signal new data event to a potentially reading application
if (fSignalNewData) {
ShbError2 = ShbIpcSignalNewData(pShbInstance_p);
if (ShbError == kShbOk) {
ShbError = ShbError2;
}
}
// signal that the last write job has been finished to allow
// a waiting application to reset the buffer now
if (fSignalReset) {
ShbError2 = ShbIpcSignalJobReady(pShbInstance_p);
if (ShbError == kShbOk) {
ShbError = ShbError2;
}
}
*pfBufferCompleted_p = fBufferCompleted;
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Read data block from Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirReadDataBlock(tShbInstance pShbInstance_p,
void *pDstDataBlock_p,
unsigned long ulRdBuffSize_p,
unsigned long *pulDataBlockSize_p)
{
tShbCirBuff *pShbCirBuff;
tShbCirBlockSize ShbCirBlockSize;
unsigned long ulDataReadable;
unsigned char *pShbCirDataPtr;
unsigned char *pDstDataPtr;
unsigned long ulDataSize = 0; // d.k. GCC complains about uninitialized variable otherwise
unsigned long ulChunkSize;
unsigned long ulRdIndex;
tShbError ShbError;
// check arguments
if ((pShbInstance_p == NULL) || (pulDataBlockSize_p == NULL)) {
return (kShbInvalidArg);
}
if ((pDstDataBlock_p == NULL) || (ulRdBuffSize_p == 0)) {
// nothing to do here
ShbError = kShbOk;
goto Exit;
}
ShbError = kShbOk;
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
pDstDataPtr = (unsigned char *)pDstDataBlock_p;
ulDataSize = 0;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
// get total number of readable bytes for the whole circular buffer
ShbIpcEnterAtomicSection(pShbInstance_p);
{
ulDataReadable = pShbCirBuff->m_ulDataReadable;
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
// if there are readable data available, then there must be at least
// one complete readable data block
if (ulDataReadable > 0) {
// get pointer to start of data area and current read index
pShbCirDataPtr = &pShbCirBuff->m_Data; // ptr to start of data area
ulRdIndex = pShbCirBuff->m_ulRdIndex;
// get real size of current block (incl. alignment fill bytes)
ShbCirBlockSize =
*(tShbCirBlockSize *) (pShbCirDataPtr + ulRdIndex);
ulRdIndex += sizeof(tShbCirBlockSize);
ulRdIndex %= pShbCirBuff->m_ulBufferDataSize;
// get size of user data inside the current block
ulDataSize =
ShbCirBlockSize.m_uiFullBlockSize -
ShbCirBlockSize.m_uiAlignFillBytes;
ulDataSize -= sizeof(tShbCirBlockSize);
}
// ulDataSize = MIN(ulDataSize, ulRdBuffSize_p);
if (ulDataSize > ulRdBuffSize_p) {
ulDataSize = ulRdBuffSize_p;
ShbError = kShbDataTruncated;
}
if (ulDataSize == 0) {
// nothing to do here
ShbError = kShbNoReadableData;
goto Exit;
}
// copy the data from the circular buffer
// (the copy process itself will be done outside of any
// critical/locked section)
if (ulRdIndex + ulDataSize <= pShbCirBuff->m_ulBufferDataSize) {
// linear read operation
memcpy(pDstDataPtr, pShbCirDataPtr + ulRdIndex, ulDataSize);
} else {
// wrap-around read operation
ulChunkSize = pShbCirBuff->m_ulBufferDataSize - ulRdIndex;
memcpy(pDstDataPtr, pShbCirDataPtr + ulRdIndex, ulChunkSize);
memcpy(pDstDataPtr + ulChunkSize, pShbCirDataPtr,
ulDataSize - ulChunkSize);
}
#ifndef NDEBUG
{
tShbCirBlockSize ClrShbCirBlockSize;
if (ulRdIndex + ulDataSize <= pShbCirBuff->m_ulBufferDataSize) {
// linear buffer
memset(pShbCirDataPtr + ulRdIndex, 0xDD, ulDataSize);
} else {
// wrap-around read operation
ulChunkSize =
pShbCirBuff->m_ulBufferDataSize - ulRdIndex;
memset(pShbCirDataPtr + ulRdIndex, 0xDD, ulChunkSize);
memset(pShbCirDataPtr, 0xDD, ulDataSize - ulChunkSize);
}
ClrShbCirBlockSize.m_uiFullBlockSize = /*(unsigned int) */ -1; // -1 = xFFFFFFF
ClrShbCirBlockSize.m_uiAlignFillBytes = /*(unsigned int) */ -1; // -1 = Fxxxxxxx
*(tShbCirBlockSize *) (pShbCirDataPtr +
pShbCirBuff->m_ulRdIndex) =
ClrShbCirBlockSize;
}
#endif // #ifndef NDEBUG
// set new size of readable data, data in use, new read index
// and adjust number of readable blocks
ShbIpcEnterAtomicSection(pShbInstance_p);
{
pShbCirBuff->m_ulDataInUse -= ShbCirBlockSize.m_uiFullBlockSize;
pShbCirBuff->m_ulDataReadable -=
ShbCirBlockSize.m_uiFullBlockSize;
pShbCirBuff->m_ulBlocksReadable--;
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
if ((pShbCirBuff->m_ulDataInUse == 0)
&& (pShbCirBuff->m_ulDataReadable == 0)) {
ASSERT(pShbCirBuff->m_ulBlocksReadable == 0);
pShbCirBuff->m_ulWrIndex = 0;
pShbCirBuff->m_ulRdIndex = 0;
} else
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
{
pShbCirBuff->m_ulRdIndex +=
ShbCirBlockSize.m_uiFullBlockSize;
pShbCirBuff->m_ulRdIndex %=
pShbCirBuff->m_ulBufferDataSize;
}
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
Exit:
*pulDataBlockSize_p = ulDataSize;
return (ShbError);
}
//---------------------------------------------------------------------------
// Get data size of next readable block from Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirGetReadDataSize(tShbInstance pShbInstance_p,
unsigned long *pulDataBlockSize_p)
{
tShbCirBuff *pShbCirBuff;
unsigned long ulDataReadable;
unsigned char *pShbCirDataPtr;
tShbCirBlockSize ShbCirBlockSize;
unsigned long ulDataSize;
tShbError ShbError;
// check arguments
if ((pShbInstance_p == NULL) || (pulDataBlockSize_p == NULL)) {
return (kShbInvalidArg);
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
ulDataSize = 0;
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
// get total number of readable bytes for the whole circular buffer
ShbIpcEnterAtomicSection(pShbInstance_p);
{
ulDataReadable = pShbCirBuff->m_ulDataReadable;
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
// if there are readable data available, then there must be at least
// one complete readable data block
if (ulDataReadable > 0) {
pShbCirDataPtr =
&pShbCirBuff->m_Data + pShbCirBuff->m_ulRdIndex;
// get real size of current block (incl. alignment fill bytes)
ShbCirBlockSize = *(tShbCirBlockSize *) pShbCirDataPtr;
// get size of user data inside the current block
ulDataSize =
ShbCirBlockSize.m_uiFullBlockSize -
ShbCirBlockSize.m_uiAlignFillBytes;
ulDataSize -= sizeof(tShbCirBlockSize);
}
Exit:
*pulDataBlockSize_p = ulDataSize;
return (ShbError);
}
//---------------------------------------------------------------------------
// Get number of readable blocks from Circular Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbCirGetReadBlockCount(tShbInstance pShbInstance_p,
unsigned long *pulDataBlockCount_p)
{
tShbCirBuff *pShbCirBuff;
unsigned long ulBlockCount;
tShbError ShbError;
// check arguments
if ((pShbInstance_p == NULL) || (pulDataBlockCount_p == NULL)) {
ShbError = kShbInvalidArg;
goto Exit;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
ulBlockCount = 0;
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
ShbIpcEnterAtomicSection(pShbInstance_p);
{
ulBlockCount = pShbCirBuff->m_ulBlocksReadable;
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
*pulDataBlockCount_p = ulBlockCount;
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Set application handler to signal new data for Circular Shared Buffer
// d.k.: new parameter priority as enum
//---------------------------------------------------------------------------
tShbError ShbCirSetSignalHandlerNewData(tShbInstance pShbInstance_p,
tShbCirSigHndlrNewData pfnSignalHandlerNewData_p,
tShbPriority ShbPriority_p)
{
tShbCirBuff *pShbCirBuff;
tShbError ShbError;
// check arguments
if (pShbInstance_p == NULL) {
ShbError = kShbInvalidArg;
goto Exit;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
if (pfnSignalHandlerNewData_p != NULL) {
// set a new signal handler
if (pShbCirBuff->m_pfnSigHndlrNewData != NULL) {
ShbError = kShbAlreadySignaling;
goto Exit;
}
pShbCirBuff->m_pfnSigHndlrNewData = pfnSignalHandlerNewData_p;
ShbError =
ShbIpcStartSignalingNewData(pShbInstance_p,
ShbCirSignalHandlerNewData,
ShbPriority_p);
} else {
// remove existing signal handler
ShbError = ShbIpcStopSignalingNewData(pShbInstance_p);
if (pShbCirBuff->m_pfnSigHndlrNewData != NULL) {
pShbCirBuff->m_pfnSigHndlrNewData(pShbInstance_p, 0);
}
pShbCirBuff->m_pfnSigHndlrNewData = NULL;
}
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// DEBUG: Trace Circular Shared Buffer
//---------------------------------------------------------------------------
#ifndef NDEBUG
tShbError ShbCirTraceBuffer(tShbInstance pShbInstance_p)
{
tShbCirBuff *pShbCirBuff;
char szMagigID[sizeof(SBC_MAGIC_ID) + 1];
tShbCirBlockSize ShbCirBlockSize;
unsigned long ulDataReadable;
unsigned char *pShbCirDataPtr;
unsigned long ulBlockIndex;
unsigned int nBlockCount;
unsigned long ulDataSize;
unsigned long ulChunkSize;
unsigned long ulRdIndex;
tShbError ShbError;
TRACE0("\n\n##### Circular Shared Buffer #####\n");
// check arguments
if (pShbInstance_p == NULL) {
TRACE1("\nERROR: invalid buffer address (0x%08lX)\n",
(unsigned long)pShbInstance_p);
ShbError = kShbInvalidArg;
goto Exit;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
*(unsigned long *)&szMagigID[0] = pShbCirBuff->m_ShbCirMagicID;
szMagigID[sizeof(SBC_MAGIC_ID)] = '\0';
ShbIpcEnterAtomicSection(pShbInstance_p);
{
TRACE1("\nBuffer Address: 0x%08lX\n",
(unsigned long)pShbCirBuff);
TRACE0("\nHeader Info:");
TRACE2("\nMagigID: '%s' (%08lX)", szMagigID,
pShbCirBuff->m_ShbCirMagicID);
TRACE1("\nBufferTotalSize: %4lu [Bytes]",
pShbCirBuff->m_ulBufferTotalSize);
TRACE1("\nBufferDataSize: %4lu [Bytes]",
pShbCirBuff->m_ulBufferDataSize);
TRACE1("\nWrIndex: %4lu", pShbCirBuff->m_ulWrIndex);
TRACE1("\nRdIndex: %4lu", pShbCirBuff->m_ulRdIndex);
TRACE1("\nNumOfWriteJobs: %4lu",
pShbCirBuff->m_ulNumOfWriteJobs);
TRACE1("\nDataInUse: %4lu [Bytes]",
pShbCirBuff->m_ulDataInUse);
TRACE1("\nDataApended: %4lu [Bytes]",
pShbCirBuff->m_ulDataApended);
TRACE1("\nBlocksApended: %4lu",
pShbCirBuff->m_ulBlocksApended);
TRACE1("\nDataReadable: %4lu [Bytes]",
pShbCirBuff->m_ulDataReadable);
TRACE1("\nBlocksReadable: %4lu",
pShbCirBuff->m_ulBlocksReadable);
TRACE1("\nSigHndlrNewData: %08lX",
(unsigned long)pShbCirBuff->m_pfnSigHndlrNewData);
TRACE1("\nBufferLocked: %d", pShbCirBuff->m_fBufferLocked);
TRACE1("\nSigHndlrReset: %08lX",
(unsigned long)pShbCirBuff->m_pfnSigHndlrReset);
ShbTraceDump(&pShbCirBuff->m_Data,
pShbCirBuff->m_ulBufferDataSize, 0x00000000L,
"\nData Area:");
ulDataReadable = pShbCirBuff->m_ulDataReadable;
nBlockCount = 1;
ulBlockIndex = pShbCirBuff->m_ulRdIndex;
while (ulDataReadable > 0) {
TRACE1("\n\n--- Block #%u ---", nBlockCount);
// get pointer to start of data area and current read index
pShbCirDataPtr = &pShbCirBuff->m_Data; // ptr to start of data area
ulRdIndex = ulBlockIndex;
// get real size of current block (incl. alignment fill bytes)
ShbCirBlockSize =
*(tShbCirBlockSize *) (pShbCirDataPtr + ulRdIndex);
ulRdIndex += sizeof(tShbCirBlockSize);
ulRdIndex %= pShbCirBuff->m_ulBufferDataSize;
// get size of user data inside the current block
ulDataSize =
ShbCirBlockSize.m_uiFullBlockSize -
ShbCirBlockSize.m_uiAlignFillBytes;
ulDataSize -= sizeof(tShbCirBlockSize);
TRACE1
("\nFull Data Size: %4u [Bytes] (incl. header and alignment fill bytes)",
ShbCirBlockSize.m_uiFullBlockSize);
TRACE1("\nUser Data Size: %4lu [Bytes]",
ulDataSize);
TRACE1("\nAlignment Fill Bytes: %4u [Bytes]",
ShbCirBlockSize.m_uiAlignFillBytes);
if (ulRdIndex + ulDataSize <=
pShbCirBuff->m_ulBufferDataSize) {
// linear data buffer
ShbTraceDump(pShbCirDataPtr + ulRdIndex,
ulDataSize, 0x00000000L, NULL);
} else {
// wrap-around data buffer
ulChunkSize =
pShbCirBuff->m_ulBufferDataSize - ulRdIndex;
ShbTraceDump(pShbCirDataPtr + ulRdIndex,
ulChunkSize, 0x00000000L, NULL);
ShbTraceDump(pShbCirDataPtr,
ulDataSize - ulChunkSize,
ulChunkSize, NULL);
}
nBlockCount++;
ulBlockIndex += ShbCirBlockSize.m_uiFullBlockSize;
ulBlockIndex %= pShbCirBuff->m_ulBufferDataSize;
ulDataReadable -= ShbCirBlockSize.m_uiFullBlockSize;
}
ASSERT(pShbCirBuff->m_ulBlocksReadable == nBlockCount - 1);
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
Exit:
return (ShbError);
}
#endif
//-------------------------------------------------------------------------//
// //
// L i n e a r S h a r e d B u f f e r //
// //
//-------------------------------------------------------------------------//
//---------------------------------------------------------------------------
// Allocate Linear Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbLinAllocBuffer(unsigned long ulBufferSize_p,
const char *pszBufferID_p,
tShbInstance * ppShbInstance_p,
unsigned int *pfShbNewCreated_p)
{
tShbInstance pShbInstance;
tShbLinBuff *pShbLinBuff;
unsigned int fShbNewCreated;
unsigned long ulBufferDataSize;
unsigned long ulBufferTotalSize;
tShbError ShbError;
// check arguments
if ((ulBufferSize_p == 0) || (ppShbInstance_p == NULL)) {
return (kShbInvalidArg);
}
// calculate length of memory to allocate
ulBufferDataSize =
(ulBufferSize_p +
(SBL_BLOCK_ALIGNMENT - 1)) & ~(SBL_BLOCK_ALIGNMENT - 1);
ulBufferTotalSize = ulBufferDataSize + sizeof(tShbLinBuff);
// allocate a new or open an existing shared buffer
ShbError = ShbIpcAllocBuffer(ulBufferTotalSize, pszBufferID_p,
&pShbInstance, &fShbNewCreated);
if (ShbError != kShbOk) {
goto Exit;
}
if (pShbInstance == NULL) {
ShbError = kShbOutOfMem;
goto Exit;
}
// get pointer to shared buffer
pShbLinBuff = (tShbLinBuff *) ShbIpcGetShMemPtr(pShbInstance);
// if the shared buffer was new created, than this process has
// to initialize it, otherwise the buffer is already in use
// and *must not* be reseted
if (fShbNewCreated) {
#ifndef NDEBUG
{
memset(pShbLinBuff, 0xCC, ulBufferTotalSize);
}
#endif
pShbLinBuff->m_ShbLinMagicID = SBL_MAGIC_ID;
pShbLinBuff->m_ulBufferTotalSize = ulBufferTotalSize;
pShbLinBuff->m_ulBufferDataSize = ulBufferDataSize;
} else {
if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
}
Exit:
*ppShbInstance_p = pShbInstance;
*pfShbNewCreated_p = fShbNewCreated;
return (ShbError);
}
//---------------------------------------------------------------------------
// Release Linear Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbLinReleaseBuffer(tShbInstance pShbInstance_p)
{
tShbError ShbError;
// check arguments
if (pShbInstance_p == NULL) {
ShbError = kShbOk;
goto Exit;
}
ShbError = ShbIpcReleaseBuffer(pShbInstance_p);
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Write data block to Linear Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbLinWriteDataBlock(tShbInstance pShbInstance_p,
unsigned long ulDstBufferOffs_p,
const void *pSrcDataBlock_p,
unsigned long ulDataBlockSize_p)
{
tShbLinBuff *pShbLinBuff;
unsigned char *pShbLinDataPtr;
unsigned char *pScrDataPtr;
unsigned long ulBufferDataSize;
tShbError ShbError;
// check arguments
if (pShbInstance_p == NULL) {
ShbError = kShbInvalidArg;
goto Exit;
}
if ((pSrcDataBlock_p == NULL) || (ulDataBlockSize_p == 0)) {
// nothing to do here
ShbError = kShbOk;
goto Exit;
}
if (ulDataBlockSize_p > SBL_MAX_BLOCK_SIZE) {
ShbError = kShbExceedDataSizeLimit;
goto Exit;
}
pShbLinBuff = ShbLinGetBuffer(pShbInstance_p);
pScrDataPtr = (unsigned char *)pSrcDataBlock_p;
ShbError = kShbOk;
if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
// check if offeset and size for the write operation matches with
// the size of the shared buffer
ulBufferDataSize = pShbLinBuff->m_ulBufferDataSize;
if ((ulDstBufferOffs_p > ulBufferDataSize) ||
(ulDataBlockSize_p > ulBufferDataSize) ||
((ulDstBufferOffs_p + ulDataBlockSize_p) > ulBufferDataSize)) {
ShbError = kShbDataOutsideBufferArea;
goto Exit;
}
// copy the data to the linear buffer
// (the copy process will be done inside of any critical/locked section)
pShbLinDataPtr = &pShbLinBuff->m_Data; // ptr to start of data area
pShbLinDataPtr += ulDstBufferOffs_p;
ShbIpcEnterAtomicSection(pShbInstance_p);
{
memcpy(pShbLinDataPtr, pScrDataPtr, ulDataBlockSize_p);
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// Read data block from Linear Shared Buffer
//---------------------------------------------------------------------------
tShbError ShbLinReadDataBlock(tShbInstance pShbInstance_p,
void *pDstDataBlock_p,
unsigned long ulSrcBufferOffs_p,
unsigned long ulDataBlockSize_p)
{
tShbLinBuff *pShbLinBuff;
unsigned char *pShbLinDataPtr;
unsigned char *pDstDataPtr;
unsigned long ulBufferDataSize;
tShbError ShbError;
// check arguments
if (pShbInstance_p == NULL) {
ShbError = kShbInvalidArg;
goto Exit;
}
if ((pDstDataBlock_p == NULL) || (ulDataBlockSize_p == 0)) {
// nothing to do here
ShbError = kShbOk;
goto Exit;
}
if (ulDataBlockSize_p > SBL_MAX_BLOCK_SIZE) {
ShbError = kShbExceedDataSizeLimit;
goto Exit;
}
pShbLinBuff = ShbLinGetBuffer(pShbInstance_p);
pDstDataPtr = (unsigned char *)pDstDataBlock_p;
ShbError = kShbOk;
if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
// check if offeset and size for the read operation matches with
// the size of the shared buffer
ulBufferDataSize = pShbLinBuff->m_ulBufferDataSize;
if ((ulSrcBufferOffs_p > ulBufferDataSize) ||
(ulDataBlockSize_p > ulBufferDataSize) ||
((ulSrcBufferOffs_p + ulDataBlockSize_p) > ulBufferDataSize)) {
ShbError = kShbDataOutsideBufferArea;
goto Exit;
}
// copy the data to the linear buffer
// (the copy process will be done inside of any critical/locked section)
pShbLinDataPtr = &pShbLinBuff->m_Data; // ptr to start of data area
pShbLinDataPtr += ulSrcBufferOffs_p;
ShbIpcEnterAtomicSection(pShbInstance_p);
{
memcpy(pDstDataPtr, pShbLinDataPtr, ulDataBlockSize_p);
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
Exit:
return (ShbError);
}
//---------------------------------------------------------------------------
// DEBUG: Trace Linear Shared Buffer
//---------------------------------------------------------------------------
#ifndef NDEBUG
tShbError ShbLinTraceBuffer(tShbInstance pShbInstance_p)
{
tShbLinBuff *pShbLinBuff;
char szMagigID[sizeof(SBL_MAGIC_ID) + 1];
tShbError ShbError;
TRACE0("\n\n##### Linear Shared Buffer #####\n");
// check arguments
if (pShbInstance_p == NULL) {
TRACE1("\nERROR: invalid buffer address (0x%08lX)\n",
(unsigned long)pShbInstance_p);
ShbError = kShbInvalidArg;
goto Exit;
}
pShbLinBuff = ShbLinGetBuffer(pShbInstance_p);
ShbError = kShbOk;
if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
ShbError = kShbInvalidBufferType;
goto Exit;
}
*(unsigned int *)&szMagigID[0] = pShbLinBuff->m_ShbLinMagicID;
szMagigID[sizeof(SBL_MAGIC_ID)] = '\0';
ShbIpcEnterAtomicSection(pShbInstance_p);
{
TRACE1("\nBuffer Address: 0x%08lX\n",
(unsigned long)pShbLinBuff);
TRACE0("\nHeader Info:");
TRACE2("\nMagigID: '%s' (%08X)", szMagigID,
pShbLinBuff->m_ShbLinMagicID);
TRACE1("\nBufferTotalSize: %4lu [Bytes]",
pShbLinBuff->m_ulBufferTotalSize);
TRACE1("\nBufferDataSize: %4lu [Bytes]",
pShbLinBuff->m_ulBufferDataSize);
ShbTraceDump(&pShbLinBuff->m_Data,
pShbLinBuff->m_ulBufferDataSize, 0x00000000L,
"\nData Area:");
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
Exit:
return (ShbError);
}
#endif
//---------------------------------------------------------------------------
// Dump buffer contents
//---------------------------------------------------------------------------
#ifndef NDEBUG
tShbError ShbTraceDump(const unsigned char *pabStartAddr_p,
unsigned long ulDataSize_p,
unsigned long ulAddrOffset_p, const char *pszInfoText_p)
{
const unsigned char *pabBuffData;
unsigned long ulBuffSize;
unsigned char bData;
int nRow;
int nCol;
// get pointer to buffer and length of buffer
pabBuffData = pabStartAddr_p;
ulBuffSize = ulDataSize_p;
if (pszInfoText_p != NULL) {
TRACE1("%s", pszInfoText_p);
}
// dump buffer contents
for (nRow = 0;; nRow++) {
TRACE1("\n%08lX: ",
(unsigned long)(nRow * 0x10) + ulAddrOffset_p);
for (nCol = 0; nCol < 16; nCol++) {
if ((unsigned long)nCol < ulBuffSize) {
TRACE1("%02X ",
(unsigned int)*(pabBuffData + nCol));
} else {
TRACE0(" ");
}
}
TRACE0(" ");
for (nCol = 0; nCol < 16; nCol++) {
bData = *pabBuffData++;
if ((unsigned long)nCol < ulBuffSize) {
if ((bData >= 0x20) && (bData < 0x7F)) {
TRACE1("%c", bData);
} else {
TRACE0(".");
}
} else {
TRACE0(" ");
}
}
if (ulBuffSize > 16) {
ulBuffSize -= 16;
} else {
break;
}
}
return (kShbOk);
}
#endif // #ifndef NDEBUG
//=========================================================================//
// //
// P R I V A T E F U N C T I O N S //
// //
//=========================================================================//
//---------------------------------------------------------------------------
// Handler to signal new data event for Circular Shared Buffer
//---------------------------------------------------------------------------
int ShbCirSignalHandlerNewData(tShbInstance pShbInstance_p)
{
tShbCirBuff *pShbCirBuff;
unsigned long ulDataSize;
unsigned long ulBlockCount;
tShbError ShbError;
// check arguments
if (pShbInstance_p == NULL) {
return FALSE;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
ShbError = kShbOk;
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
return FALSE;
}
// call application handler
if (pShbCirBuff->m_pfnSigHndlrNewData != NULL) {
/* do
{*/
ShbError = ShbCirGetReadDataSize(pShbInstance_p, &ulDataSize);
if ((ulDataSize > 0) && (ShbError == kShbOk)) {
pShbCirBuff->m_pfnSigHndlrNewData(pShbInstance_p,
ulDataSize);
}
ShbError =
ShbCirGetReadBlockCount(pShbInstance_p, &ulBlockCount);
/* }
while ((ulBlockCount > 0) && (ShbError == kShbOk));*/
}
// Return TRUE if there are pending blocks.
// In that case ShbIpc tries to call this function again immediately if there
// is no other filled shared buffer with higher priority.
return ((ulBlockCount > 0) && (ShbError == kShbOk));
}
//---------------------------------------------------------------------------
// Handler to reset Circular Shared Buffer
//---------------------------------------------------------------------------
void ShbCirSignalHandlerReset(tShbInstance pShbInstance_p,
unsigned int fTimeOut_p)
{
tShbCirBuff *pShbCirBuff;
// check arguments
if (pShbInstance_p == NULL) {
return;
}
pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
return;
}
// reset buffer header
if (!fTimeOut_p) {
ShbIpcEnterAtomicSection(pShbInstance_p);
{
pShbCirBuff->m_ulWrIndex = 0;
pShbCirBuff->m_ulRdIndex = 0;
pShbCirBuff->m_ulNumOfWriteJobs = 0;
pShbCirBuff->m_ulDataInUse = 0;
pShbCirBuff->m_ulDataApended = 0;
pShbCirBuff->m_ulBlocksApended = 0;
pShbCirBuff->m_ulDataReadable = 0;
pShbCirBuff->m_ulBlocksReadable = 0;
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
#ifndef NDEBUG
{
memset(&pShbCirBuff->m_Data, 0xCC,
pShbCirBuff->m_ulBufferDataSize);
}
#endif
}
// call application handler
if (pShbCirBuff->m_pfnSigHndlrReset != NULL) {
pShbCirBuff->m_pfnSigHndlrReset(pShbInstance_p, fTimeOut_p);
}
// unlock buffer
ShbIpcEnterAtomicSection(pShbInstance_p);
{
pShbCirBuff->m_fBufferLocked = FALSE;
pShbCirBuff->m_pfnSigHndlrReset = NULL;
}
ShbIpcLeaveAtomicSection(pShbInstance_p);
return;
}
// EOF