/* * $Id$ * * * 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 #include #include "epicsAssert.h" #include "epicsTypes.h" #include "tsFreeList.h" #include "tsDLList.h" #include "osiWireFormat.h" static const unsigned comBufSize = 0x4000; class wireSendAdapter { public: virtual unsigned sendBytes ( const void *pBuf, unsigned nBytesInBuf ) = 0; virtual void forcedShutdown () = 0; }; class wireRecvAdapter { public: virtual unsigned recvBytes ( void *pBuf, unsigned nBytesInBuf ) = 0; }; class comBuf : public tsDLNode < comBuf > { public: comBuf (); void destroy (); unsigned unoccupiedBytes () const; unsigned occupiedBytes () const; static unsigned capacityBytes (); void clear (); unsigned copyInBytes ( const void *pBuf, unsigned nBytes ); unsigned copyIn ( comBuf & ); unsigned copyIn ( const epicsInt8 *pValue, unsigned nElem ); unsigned copyIn ( const epicsUInt8 *pValue, unsigned nElem ); unsigned copyIn ( const epicsInt16 *pValue, unsigned nElem ); unsigned copyIn ( const epicsUInt16 *pValue, unsigned nElem ); unsigned copyIn ( const epicsInt32 *pValue, unsigned nElem ); unsigned copyIn ( const epicsUInt32 *pValue, unsigned nElem ); unsigned copyIn ( const epicsFloat32 *pValue, unsigned nElem ); unsigned copyIn ( const epicsFloat64 *pValue, unsigned nElem ); unsigned copyIn ( const epicsOldString *pValue, unsigned nElem ); bool copyInAllBytes ( const void *pBuf, unsigned nBytes ); unsigned copyOutBytes ( void *pBuf, unsigned nBytes ); bool copyOutAllBytes ( void *pBuf, unsigned nBytes ); unsigned removeBytes ( unsigned nBytes ); void * operator new ( size_t size, const std::nothrow_t & ); void operator delete ( void *pCadaver, size_t size ); bool flushToWire ( wireSendAdapter & ); unsigned fillFromWire ( wireRecvAdapter & ); epicsUInt8 popUInt8 (); struct statusPopUInt16 { epicsUInt16 val; bool success; }; statusPopUInt16 popUInt16 (); struct statusPopUInt32 { epicsUInt32 val; bool success; }; statusPopUInt32 popUInt32 (); class insufficentBytesAvailable {}; protected: ~comBuf (); private: unsigned nextWriteIndex; unsigned nextReadIndex; epicsUInt8 buf [ comBufSize ]; unsigned unoccupiedElem ( unsigned elemSize, unsigned nElem ); unsigned occupiedElem ( unsigned elemSize, unsigned nElem ); static tsFreeList < class comBuf, 0x20 > freeList; static epicsMutex freeListMutex; }; inline comBuf::comBuf () : nextWriteIndex ( 0u ), nextReadIndex ( 0u ) { } inline comBuf::~comBuf () { } inline void comBuf::destroy () { delete this; } inline void comBuf::clear () { this->nextWriteIndex = 0u; this->nextReadIndex = 0u; } inline void * comBuf::operator new ( size_t size, const std::nothrow_t & ) { epicsAutoMutex locker ( comBuf::freeListMutex ); return comBuf::freeList.allocate ( size ); } inline void comBuf::operator delete ( void *pCadaver, size_t size ) { epicsAutoMutex locker ( comBuf::freeListMutex ); comBuf::freeList.release ( pCadaver, size ); } inline unsigned comBuf::unoccupiedBytes () const { return sizeof ( this->buf ) - this->nextWriteIndex; } inline unsigned comBuf::occupiedBytes () const { // assert (this->nextWriteIndex >= this->nextReadIndex); return this->nextWriteIndex - this->nextReadIndex; } inline bool comBuf::copyInAllBytes ( const void *pBuf, unsigned nBytes ) { if ( nBytes <= this->unoccupiedBytes () ) { memcpy ( &this->buf[this->nextWriteIndex], pBuf, nBytes); this->nextWriteIndex += nBytes; return true; } return false; } inline unsigned comBuf::copyInBytes ( const void *pBuf, unsigned nBytes ) { if ( nBytes > 0u ) { unsigned available = this->unoccupiedBytes (); if ( nBytes > available ) { nBytes = available; } memcpy ( &this->buf[this->nextWriteIndex], pBuf, nBytes); this->nextWriteIndex += nBytes; } return nBytes; } inline unsigned comBuf::copyIn ( comBuf &bufIn ) { unsigned nBytes = this->copyInBytes ( &bufIn.buf[bufIn.nextReadIndex], bufIn.nextWriteIndex - bufIn.nextReadIndex ); bufIn.nextReadIndex += nBytes; return nBytes; } inline bool comBuf::copyOutAllBytes ( void *pBuf, unsigned nBytes ) { if ( nBytes <= this->occupiedBytes () ) { memcpy ( pBuf, &this->buf[this->nextReadIndex], nBytes); this->nextReadIndex += nBytes; return true; } return false; } inline unsigned comBuf::copyOutBytes ( void *pBuf, unsigned nBytes ) { unsigned occupied = this->occupiedBytes (); if ( nBytes > occupied ) { nBytes = occupied; } memcpy ( pBuf, &this->buf[this->nextReadIndex], nBytes); this->nextReadIndex += nBytes; return nBytes; } inline unsigned comBuf::removeBytes ( unsigned nBytes ) { unsigned occupied = this->occupiedBytes (); if ( nBytes > occupied ) { nBytes = occupied; } this->nextReadIndex += nBytes; return nBytes; } inline unsigned comBuf::capacityBytes () { return comBufSize; } inline unsigned comBuf::fillFromWire ( wireRecvAdapter &wire ) { unsigned nNewBytes = wire.recvBytes ( &this->buf[this->nextWriteIndex], sizeof ( this->buf ) - this->nextWriteIndex ); this->nextWriteIndex += nNewBytes; return nNewBytes; } inline unsigned comBuf::unoccupiedElem ( unsigned elemSize, unsigned nElem ) { unsigned avail = this->unoccupiedBytes (); if ( elemSize * nElem > avail ) { return avail / elemSize; } else { return nElem; } } inline unsigned comBuf::copyIn ( const epicsInt8 *pValue, unsigned nElem ) { return copyInBytes ( pValue, nElem ); } inline unsigned comBuf::copyIn ( const epicsUInt8 *pValue, unsigned nElem ) { return copyInBytes ( pValue, nElem ); } inline unsigned comBuf::copyIn ( const epicsInt16 *pValue, unsigned nElem ) { nElem = this->unoccupiedElem ( sizeof (*pValue), nElem ); for ( unsigned i = 0u; i < nElem; i++ ) { this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 8u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 0u ); } return nElem; } inline unsigned comBuf::copyIn ( const epicsUInt16 *pValue, unsigned nElem ) { nElem = this->unoccupiedElem ( sizeof (*pValue), nElem ); for ( unsigned i = 0u; i < nElem; i++ ) { this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 8u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 0u ); } return nElem; } inline unsigned comBuf::copyIn ( const epicsInt32 *pValue, unsigned nElem ) { nElem = this->unoccupiedElem ( sizeof (*pValue), nElem ); for ( unsigned i = 0u; i < nElem; i++ ) { this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 24u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 16u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 8u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 0u ); } return nElem; } inline unsigned comBuf::copyIn ( const epicsUInt32 *pValue, unsigned nElem ) { nElem = this->unoccupiedElem ( sizeof (*pValue), nElem ); for ( unsigned i = 0u; i < nElem; i++ ) { this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 24u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 16u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 8u ); this->buf[this->nextWriteIndex++] = static_cast < char > ( pValue[i] >> 0u ); } return nElem; } inline unsigned comBuf::copyIn ( const epicsFloat32 *pValue, unsigned nElem ) { nElem = this->unoccupiedElem ( sizeof (*pValue), nElem ); for ( unsigned i = 0u; i < nElem; i++ ) { // allow native floating point formats to be converted to IEEE osiConvertToWireFormat ( pValue[i], &this->buf[this->nextWriteIndex] ); this->nextWriteIndex += sizeof ( *pValue ); } return nElem; } inline unsigned comBuf::copyIn ( const epicsFloat64 *pValue, unsigned nElem ) { nElem = this->unoccupiedElem ( sizeof (*pValue), nElem ); for ( unsigned i = 0u; i < nElem; i++ ) { // allow native floating point formats to be converted to IEEE osiConvertToWireFormat ( pValue[i], &this->buf[this->nextWriteIndex] ); this->nextWriteIndex += sizeof ( *pValue ); } return nElem; } inline unsigned comBuf::copyIn ( const epicsOldString *pValue, unsigned nElem ) { nElem = this->unoccupiedElem ( sizeof (*pValue), nElem ); unsigned size = nElem * sizeof ( *pValue ); memcpy ( &this->buf[ this->nextWriteIndex ], pValue, size ); this->nextWriteIndex += size; return nElem; } inline unsigned comBuf::occupiedElem ( unsigned elemSize, unsigned nElem ) { unsigned avail = this->occupiedBytes (); if ( elemSize * nElem > avail ) { return avail / elemSize; } else { return nElem; } } inline epicsUInt8 comBuf::popUInt8 () { if ( this->occupiedBytes () ) { return this->buf[ this->nextReadIndex++ ]; } else { throw insufficentBytesAvailable (); } } inline comBuf::statusPopUInt16 comBuf::popUInt16 () { statusPopUInt16 tmp; if ( this->occupiedBytes () >= 2u ) { tmp.val = this->buf[ this->nextReadIndex++ ] << 8u; tmp.val |= this->buf[ this->nextReadIndex++ ] << 0u; tmp.success = true; } else { tmp.val = 0xffff; tmp.success = false; } return tmp; } inline comBuf::statusPopUInt32 comBuf::popUInt32 () { statusPopUInt32 tmp; if ( this->occupiedBytes () >= 4u ) { tmp.val = this->buf[ this->nextReadIndex++ ] << 24u; tmp.val |= this->buf[ this->nextReadIndex++ ] << 16u; tmp.val |= this->buf[ this->nextReadIndex++ ] << 8u; tmp.val |= this->buf[ this->nextReadIndex++ ] << 0u; tmp.success = true; } else { tmp.val = 0xffffffff; tmp.success = false; } return tmp; } #endif // ifndef comBufh