Files
epics-base/src/ca/comBuf.h
2004-10-04 18:55:40 +00:00

496 lines
14 KiB
C++

/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#ifndef comBufh
#define comBufh
#include <new>
#include <string.h>
#include "epicsAssert.h"
#include "epicsTypes.h"
#include "tsFreeList.h"
#include "tsDLList.h"
#include "osiWireFormat.h"
#include "compilerDependencies.h"
static const unsigned comBufSize = 0x4000;
// this wrapper avoids Tornado 2.0.1 compiler bugs
class comBufMemoryManager {
public:
virtual ~comBufMemoryManager ();
virtual void * allocate ( size_t ) = 0;
virtual void release ( void * ) = 0;
};
class wireSendAdapter { // X aCC 655
public:
virtual unsigned sendBytes ( const void * pBuf,
unsigned nBytesInBuf,
const class epicsTime & currentTime ) = 0;
};
enum swioCircuitState {
swioConnected,
swioPeerHangup,
swioPeerAbort,
swioLinkFailure,
swioLocalAbort
};
struct statusWireIO {
unsigned bytesCopied;
swioCircuitState circuitState;
};
class wireRecvAdapter { // X aCC 655
public:
virtual void recvBytes ( void * pBuf,
unsigned nBytesInBuf, statusWireIO & ) = 0;
};
class comBuf : public tsDLNode < comBuf > {
public:
class insufficentBytesAvailable {};
comBuf ();
unsigned unoccupiedBytes () const;
unsigned occupiedBytes () const;
unsigned uncommittedBytes () const;
static unsigned capacityBytes ();
void clear ();
unsigned copyInBytes ( const void *pBuf, unsigned nBytes );
unsigned push ( comBuf & );
bool push ( const epicsInt8 value );
bool push ( const epicsUInt8 value );
bool push ( const epicsInt16 value );
bool push ( const epicsUInt16 value );
bool push ( const epicsInt32 value );
bool push ( const epicsUInt32 value );
bool push ( const epicsFloat32 & value );
bool push ( const epicsFloat64 & value );
bool push ( const epicsOldString & value );
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
unsigned push ( const epicsInt16 * pValue, unsigned nElem );
unsigned push ( const epicsUInt16 * pValue, unsigned nElem );
unsigned push ( const epicsInt32 * pValue, unsigned nElem );
unsigned push ( const epicsUInt32 * pValue, unsigned nElem );
unsigned push ( const epicsFloat32 * pValue, unsigned nElem );
unsigned push ( const epicsFloat64 * pValue, unsigned nElem );
unsigned push ( const epicsOldString * pValue, unsigned nElem );
void commitIncomming ();
void clearUncommittedIncomming ();
bool copyInAllBytes ( const void *pBuf, unsigned nBytes );
unsigned copyOutBytes ( void *pBuf, unsigned nBytes );
bool copyOutAllBytes ( void *pBuf, unsigned nBytes );
unsigned removeBytes ( unsigned nBytes );
bool flushToWire ( wireSendAdapter &, const epicsTime & currentTime );
void fillFromWire ( wireRecvAdapter &, statusWireIO & );
struct popStatus {
bool success;
bool nowEmpty;
};
popStatus pop ( epicsUInt8 & );
popStatus pop ( epicsUInt16 & );
popStatus pop ( epicsUInt32 & );
static void throwInsufficentBytesException ();
void * operator new ( size_t size,
comBufMemoryManager & );
epicsPlacementDeleteOperator (( void *, comBufMemoryManager & ))
private:
unsigned commitIndex;
unsigned nextWriteIndex;
unsigned nextReadIndex;
epicsUInt8 buf [ comBufSize ];
void * operator new ( size_t size );
void operator delete ( void * );
};
inline void * comBuf::operator new ( size_t size,
comBufMemoryManager & mgr )
{
return mgr.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
inline void comBuf::operator delete ( void * pCadaver,
comBufMemoryManager & mgr )
{
mgr.release ( pCadaver );
}
#endif
inline comBuf::comBuf () : commitIndex ( 0u ),
nextWriteIndex ( 0u ), nextReadIndex ( 0u )
{
}
inline void comBuf::clear ()
{
this->commitIndex = 0u;
this->nextWriteIndex = 0u;
this->nextReadIndex = 0u;
}
inline unsigned comBuf::unoccupiedBytes () const
{
return sizeof ( this->buf ) - this->nextWriteIndex;
}
inline unsigned comBuf::occupiedBytes () const
{
return this->commitIndex - this->nextReadIndex;
}
inline unsigned comBuf::uncommittedBytes () const
{
return this->nextWriteIndex - this->commitIndex;
}
inline unsigned comBuf::push ( comBuf & bufIn )
{
unsigned nBytes = this->copyInBytes (
& bufIn.buf[ bufIn.nextReadIndex ],
bufIn.commitIndex - bufIn.nextReadIndex );
bufIn.nextReadIndex += nBytes;
return nBytes;
}
inline unsigned comBuf::capacityBytes ()
{
return comBufSize;
}
inline void comBuf::fillFromWire (
wireRecvAdapter & wire, statusWireIO & stat )
{
wire.recvBytes (
& this->buf[this->nextWriteIndex],
sizeof ( this->buf ) - this->nextWriteIndex, stat );
if ( stat.circuitState == swioConnected ) {
this->nextWriteIndex += stat.bytesCopied;
}
}
inline bool comBuf::push ( const epicsInt8 value )
{
unsigned index = this->nextWriteIndex;
unsigned nextIndex = index + sizeof ( value );
if ( nextIndex <= sizeof ( this->buf ) ) {
this->buf[ index ] = static_cast < epicsUInt8 > ( value );
this->nextWriteIndex = nextIndex;
return true;
}
return false;
}
inline bool comBuf::push ( const epicsUInt8 value )
{
unsigned index = this->nextWriteIndex;
unsigned nextIndex = index + sizeof ( value );
if ( nextIndex <= sizeof ( this->buf ) ) {
this->buf[ index ] = value;
this->nextWriteIndex = nextIndex;
return true;
}
return false;
}
inline bool comBuf::push ( const epicsInt16 value )
{
unsigned index = this->nextWriteIndex;
unsigned nextIndex = index + sizeof ( value );
if ( nextIndex <= sizeof ( this->buf ) ) {
this->buf[ index + 0u ] =
static_cast < epicsUInt8 > ( value >> 8u );
this->buf[ index + 1u ] =
static_cast < epicsUInt8 > ( value >> 0u );
this->nextWriteIndex = nextIndex;
return true;
}
return false;
}
inline bool comBuf::push ( const epicsUInt16 value )
{
unsigned index = this->nextWriteIndex;
unsigned nextIndex = index + sizeof ( value );
if ( nextIndex <= sizeof ( this->buf ) ) {
this->buf[ index + 0u ] =
static_cast < epicsUInt8 > ( value >> 8u );
this->buf[ index + 1u ] =
static_cast < epicsUInt8 > ( value >> 0u );
this->nextWriteIndex = nextIndex;
return true;
}
return false;
}
inline bool comBuf::push ( const epicsInt32 value )
{
unsigned index = this->nextWriteIndex;
unsigned nextIndex = index + sizeof ( value );
if ( nextIndex <= sizeof ( this->buf ) ) {
this->buf[ index + 0u ] =
static_cast < epicsUInt8 > ( value >> 24u );
this->buf[ index + 1u ] =
static_cast < epicsUInt8 > ( value >> 16u );
this->buf[ index + 2u ] =
static_cast < epicsUInt8 > ( value >> 8u );
this->buf[ index + 3u ] =
static_cast < epicsUInt8 > ( value >> 0u );
this->nextWriteIndex = nextIndex;
return true;
}
return false;
}
inline bool comBuf::push ( const epicsUInt32 value )
{
unsigned index = this->nextWriteIndex;
unsigned nextIndex = index + sizeof ( value );
if ( nextIndex <= sizeof ( this->buf ) ) {
this->buf[ index + 0u ] =
static_cast < epicsUInt8 > ( value >> 24u );
this->buf[ index + 1u ] =
static_cast < epicsUInt8 > ( value >> 16u );
this->buf[ index + 2u ] =
static_cast < epicsUInt8 > ( value >> 8u );
this->buf[ index + 3u ] =
static_cast < epicsUInt8 > ( value >> 0u );
this->nextWriteIndex = nextIndex;
return true;
}
return false;
}
inline bool comBuf::push ( const epicsFloat32 & value )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( sizeof ( value ) > available ) {
return false;
}
// allow native floating point formats to be converted to IEEE
osiConvertToWireFormat ( value, & this->buf[index] );
this->nextWriteIndex = index + sizeof ( value );
return true;
}
inline bool comBuf::push ( const epicsFloat64 & value )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( sizeof ( value ) > available ) {
return false;
}
// allow native floating point formats to be converted to IEEE
osiConvertToWireFormat ( value, & this->buf[index] );
this->nextWriteIndex = index + sizeof ( value );
return true;
}
inline bool comBuf::push ( const epicsOldString & value )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( sizeof ( value ) > available ) {
return false;
}
memcpy ( &this->buf[ index ], & value, sizeof ( value ) );
this->nextWriteIndex = index + sizeof ( value );
return true;
}
inline unsigned comBuf::push ( const epicsInt8 *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf::push ( const epicsUInt8 *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf::push ( const epicsOldString * pValue, unsigned nElem )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
unsigned nBytes = sizeof ( *pValue ) * nElem;
if ( nBytes > available ) {
nElem = available / sizeof ( *pValue );
nBytes = nElem * sizeof ( *pValue );
}
memcpy ( &this->buf[ index ], pValue, nBytes );
this->nextWriteIndex = index + nBytes;
return nElem;
}
inline void comBuf::commitIncomming ()
{
this->commitIndex = this->nextWriteIndex;
}
inline void comBuf::clearUncommittedIncomming ()
{
this->nextWriteIndex = this->commitIndex;
}
inline bool comBuf::copyInAllBytes ( const void *pBuf, unsigned nBytes )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( nBytes <= available ) {
memcpy ( & this->buf[index], pBuf, nBytes );
this->nextWriteIndex = index + nBytes;
return true;
}
return false;
}
inline unsigned comBuf::copyInBytes ( const void * pBuf, unsigned nBytes )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( nBytes > available ) {
nBytes = available;
}
memcpy ( & this->buf[index], pBuf, nBytes );
this->nextWriteIndex = index + nBytes;
return nBytes;
}
inline bool comBuf::copyOutAllBytes ( void * pBuf, unsigned nBytes )
{
unsigned index = this->nextReadIndex;
unsigned occupied = this->commitIndex - index;
if ( nBytes <= occupied ) {
memcpy ( pBuf, &this->buf[index], nBytes);
this->nextReadIndex = index + nBytes;
return true;
}
return false;
}
inline unsigned comBuf::copyOutBytes ( void *pBuf, unsigned nBytes )
{
unsigned index = this->nextReadIndex;
unsigned occupied = this->commitIndex - index;
if ( nBytes > occupied ) {
nBytes = occupied;
}
memcpy ( pBuf, &this->buf[index], nBytes);
this->nextReadIndex = index + nBytes;
return nBytes;
}
inline unsigned comBuf::removeBytes ( unsigned nBytes )
{
unsigned index = this->nextReadIndex;
unsigned occupied = this->commitIndex - index;
if ( nBytes > occupied ) {
nBytes = occupied;
}
this->nextReadIndex = index + nBytes;
return nBytes;
}
inline comBuf::popStatus comBuf::pop ( epicsUInt8 & returnVal )
{
unsigned nrIndex = this->nextReadIndex;
unsigned popIndex = nrIndex + sizeof ( returnVal );
unsigned cIndex = this->commitIndex;
popStatus status;
status.success = true;
status.nowEmpty = false;
if ( popIndex >= cIndex ) {
if ( popIndex == cIndex ) {
status.nowEmpty = true;
}
else {
status.success = false;
return status;
}
}
returnVal = this->buf[ nrIndex ];
this->nextReadIndex = popIndex;
return status;
}
inline comBuf::popStatus comBuf::pop ( epicsUInt16 & returnVal )
{
unsigned nrIndex = this->nextReadIndex;
unsigned popIndex = nrIndex + sizeof ( returnVal );
unsigned cIndex = this->commitIndex;
popStatus status;
status.success = true;
status.nowEmpty = false;
if ( popIndex >= cIndex ) {
if ( popIndex == cIndex ) {
status.nowEmpty = true;
}
else {
status.success = false;
return status;
}
}
returnVal =
static_cast < epicsUInt16 > (
( this->buf[ nrIndex + 0 ] << 8u ) |
this->buf[ nrIndex + 1 ]
);
this->nextReadIndex = popIndex;
return status;
}
inline comBuf::popStatus comBuf::pop ( epicsUInt32 & returnVal )
{
unsigned nrIndex = this->nextReadIndex;
unsigned popIndex = nrIndex + sizeof ( returnVal );
unsigned cIndex = this->commitIndex;
popStatus status;
status.success = true;
status.nowEmpty = false;
if ( popIndex >= cIndex ) {
if ( popIndex == cIndex ) {
status.nowEmpty = true;
}
else {
status.success = false;
return status;
}
}
returnVal =
static_cast < epicsUInt32 > (
( this->buf[ nrIndex + 0 ] << 24u ) |
( this->buf[ nrIndex + 1 ] << 16u ) |
( this->buf[ nrIndex + 2 ] << 8u ) |
this->buf[ nrIndex + 3 ]
);
this->nextReadIndex = popIndex;
return status;
}
#endif // ifndef comBufh