diff --git a/BufferCore.cpp b/BufferCore.cpp new file mode 100644 index 0000000..6673fb7 --- /dev/null +++ b/BufferCore.cpp @@ -0,0 +1,329 @@ +/* + * BufferCore.cpp + * + * Created on: 18 May 2016 + * Author: wentzelc + */ + +// redA Libraries +#include "BufferCore.h" + +// Standard C/C++ Libraries +#include +#include +#include +#include + +//--------------------------------------------------------------------------- + +CBuffer::CBuffer( int BufferSize ) : BufSize( BufferSize ) +{ + // Create Buffer + if (BufSize) { + Buffer = (char *)malloc( BufSize+1 ); + OutBuffer = (char *)malloc( BufSize+1 ); + } + else { + Buffer = NULL; + OutBuffer = NULL; + } + + // Set pointers + BufStart = 0; + BufEnd = 0; + BufLen = 0; +} +//--------------------------------------------------------------------------- + +CBuffer::~CBuffer() +{ + // Destroy Buffer + if (Buffer) { + free( Buffer ); + } + if (OutBuffer) { + free( OutBuffer ); + } +} +//--------------------------------------------------------------------------- + +// Over write existing buffer with new data +int CBuffer::Set( char * Data, int Len ) +{ + // Validate data + if (!Data || !Len) + return 0; + + if (Len <= BufSize) { + memcpy( Buffer, Data, Len ); + BufStart = 0; + BufEnd = Len; + BufLen = Len; + } + else { + memcpy( Buffer, &Data[Len-BufSize], BufSize ); + BufStart = 0; + BufEnd = 0; + BufLen = BufSize; + } + return BufLen; +} +//--------------------------------------------------------------------------- + +// Return "stitched" buffer data in temporary buffer +int CBuffer::Get( char ** Data, int MaxLen ) +{ + int BytesReturned = 0; + + // Check if any data + if (!BufLen || !MaxLen) { + *Data = NULL; + return 0; + } + + // Validate MaxLen + if ((MaxLen == -1) || (MaxLen > BufSize)) { + MaxLen = BufSize; + } + BytesReturned = (MaxLen > BufLen)? BufLen : MaxLen; + + // Copy Data from Buffer + if (BufStart + BytesReturned < BufSize) { + memcpy( OutBuffer, &Buffer[BufStart], BytesReturned ); + } + else { + memcpy( OutBuffer, &Buffer[BufStart], BufSize-BufStart ); // Copy from end of buffer + memcpy( &OutBuffer[BufSize-BufStart], Buffer, (BytesReturned-(BufSize-BufStart)) ); // Copy rollover from start of buffer + } + OutBuffer[BytesReturned] = 0; + + // Return Temp buffer + *Data = OutBuffer; + return BytesReturned; +} +//--------------------------------------------------------------------------- + +int CBuffer::Clear( int ClearLen ) +{ + int BytesCleared; + + // Validate ClearLen + BytesCleared = (ClearLen > BufSize)? BufSize : ClearLen; + + // Update Buffer pointers + if (BufStart + BytesCleared < BufSize) { + BufStart += BytesCleared; + } else { + BufStart = (BytesCleared-(BufSize-BufStart)); // Copy roll-over from start of buffer + } + BufLen -= BytesCleared; + + return BytesCleared; +} + +//--------------------------------------------------------------------------- + +int CBuffer::Reset() +{ + int BytesCleared = 0; + + // Clear all data + BytesCleared = BufLen; + BufStart = 0; + BufEnd = 0; + BufLen = 0; + + return BytesCleared; +} +//--------------------------------------------------------------------------- + +// Add bytes to end of buffer +// Return "stitched" buffer data in temporary buffer +int CBuffer::Push( char * Data, int Len ) +{ + int BytesPushed = 0; + int TotalPushed = 0; + int BufRemain = 0; + int DataRemain = Len; + + // Check if buffer created + if (!BufSize) { + return 0; + } + + // Read Data into buffer + while (TotalPushed < Len) + { + // Read from file descriptor + BufRemain = BufSize - BufEnd; + BytesPushed = ((BufRemain > DataRemain)? DataRemain : BufRemain); + memcpy( &Buffer[BufEnd], &Data[TotalPushed], BytesPushed ); + + // Update Data Pointers + TotalPushed += BytesPushed; + DataRemain -= BytesPushed; + + // Update Buffer Pointers + BufLen += BytesPushed; + BufEnd += BytesPushed; + if (BufEnd >= BufSize) { + // Rolling over end of buffer, start at beginning + BufEnd = 0; + } + if (BufLen > BufSize) { + // Head is caught up with tail, move tail up + BufLen = BufSize; + BufStart = BufEnd; + } + } + + return TotalPushed; +} +//--------------------------------------------------------------------------- + +// Read first-in bytes from buffer +// Return "stitched" buffer data in temporary buffer +int CBuffer::Pop( char ** Data, int MaxLen ) +{ + int BytesWritten = 0; + + // Read data + BytesWritten = Get( Data, MaxLen ); + + // Clear bytes + Clear( BytesWritten ); + + // Return temp buffer + return BytesWritten; +} +//--------------------------------------------------------------------------- + +// Read File descriptor directly into rolling buffer +int CBuffer::ReadFD( int Handle, int MaxRead ) +{ + int BytesRead = 0; + int TotalRead = 0; + int BufRemain = 0; + int DataRemain = 0; + + // Check if buffer created + if (!BufSize) { + return 0; + } + + // Read file descriptor into buffer + DataRemain = (MaxRead == -1)? BufSize : MaxRead; + while (DataRemain) + { + // Read from file descriptor + BufRemain = BufSize - BufEnd; + BytesRead = read( Handle, &Buffer[BufEnd], ((BufRemain > DataRemain)? DataRemain : BufRemain) ); + if (BytesRead <= 0) + break; + + // Update Buffer Pointers + DataRemain -= BytesRead; + TotalRead += BytesRead; + BufLen += BytesRead; + BufEnd += BytesRead; + if (BufEnd >= BufSize) { + // Rolling over end of buffer, start at beginning + BufEnd = 0; + } + if (BufLen > BufSize) { + // Head is caught up with tail, move tail up + BufLen = BufSize; + BufStart = BufEnd; + } + } + + return TotalRead; +} +//--------------------------------------------------------------------------- + +// Write given number of bytes directly from buffer to File descriptor +int CBuffer::WriteFD( int Handle, int MaxLen ) +{ + int BytesWritten = 0; + int TotalWritten = 0; + int BufRemain = 0; + int DataRemain = 0; + + // Check if buffer created + if (!BufSize) { + return 0; + } + + // Read Data into buffer + DataRemain = (MaxLen == -1)? BufLen : MaxLen; + while ((TotalWritten < MaxLen) && (BufLen > 0)) + { + // Read from file descriptor + BufRemain = BufSize - BufStart; + BytesWritten = write( Handle, &Buffer[BufStart], ((BufRemain > DataRemain)? DataRemain : BufRemain) ); + if (BytesWritten <= 0) + break; + + // Update Data Pointers + TotalWritten += BytesWritten; + DataRemain -= BytesWritten; + + // Update Buffer Pointers + BufLen -= BytesWritten; + BufStart += BytesWritten; + if (BufStart >= BufSize) { + // Rolling over end of buffer, start at beginning + BufStart = 0; + } + } + + return TotalWritten; +} +//--------------------------------------------------------------------------- + +// Return specific character for current rolling data +char CBuffer::GetChar( int Pos ) +{ + if (!BufLen) { + return 0; + } + else if (BufStart + Pos < BufSize) { + return Buffer[ BufStart+Pos ]; + } + else { + return Buffer[ BufStart+Pos-BufSize ]; + } +} +//--------------------------------------------------------------------------- + +// Look for first occureance of character in buffer +bool CBuffer::FindChar( char SearchChar, int &Pos ) +{ + char * CheckPos; + char * Limit; + + // Check if buffer exists + if (!BufLen) { + return false; + } + + // Search for char + Pos = 0; + CheckPos = &Buffer[BufStart]; + Limit = &Buffer[BufSize-1]; + while (Pos < BufLen) + { + if (*CheckPos == SearchChar) + return true; + + // Next char + Pos++; + if (CheckPos == Limit) { + CheckPos = Buffer; // Roll-over, Start at beginning of buffer + } else { + CheckPos++; + } + } + return false; +} +//--------------------------------------------------------------------------- diff --git a/BufferCore.h b/BufferCore.h new file mode 100644 index 0000000..ff30b26 --- /dev/null +++ b/BufferCore.h @@ -0,0 +1,64 @@ +/* + * BufferCore.h + * + * Created on: 18 May 2016 + * Author: wentzelc + */ + +#ifndef REDACORE_BUFFERCORE_H_ +#define REDACORE_BUFFERCORE_H_ + +// redA Libraries +/* none */ + +// Standard C/C++ Libraries +/* none */ + +//--------------------------------------------------------------------------- + +class CBuffer +{ +private: + // Buffer Definition + char * Buffer; // Memory allocated to buffer + int BufSize; // Size of allocated buffer + + // Buffer pointers + int BufStart; // First unread characters on buffer + int BufEnd; // Next write position for new data (End of unread data + 1) + int BufLen; // Total unread characters on buffer + + // Temporary output buffer + char * OutBuffer; // Temporary output buffer for "stitched" (rollover) data + +public: + // Life Cycle + CBuffer( int BufferSize ); + ~CBuffer(); + + // Direct Operations + int Reset(); + int Set( char * Data, int Len ); + int Get( char ** Data, int MaxLen = -1 ); + int Clear( int ClearLen ); + + // FiFo operations + int Push( char * Data, int Len ); + int Pop( char ** Data, int MaxLen = -1 ); + + // File operations + int ReadFD( int Handle, int MaxRead = -1 ); + int WriteFD( int Handle, int MaxWrite = -1 ); + + // Character Operations + char GetChar( int Pos ); + bool FindChar( char SearchChar, int &Pos ); + + // Miscellaneous + int Size() { return BufSize; }; + int Len() { return BufLen; }; +}; + +//--------------------------------------------------------------------------- + +#endif /* REDACORE_BUFFERCORE_H_ */ diff --git a/CMakeLists.txt b/CMakeLists.txt index fa308e1..e65b14a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,3 @@ PROJECT(lib_redAcore) -ADD_LIBRARY(redAcore LogCore.cpp SignalCore.cpp TimingCore.cpp PortCore.cpp SocketCore.cpp SelectCore.cpp) +ADD_LIBRARY(redAcore TimingCore.cpp LogCore.cpp BufferCore.cpp SignalCore.cpp PortCore.cpp SocketCore.cpp SelectCore.cpp) diff --git a/PortCore.cpp b/PortCore.cpp index d2a2b1c..849c069 100644 --- a/PortCore.cpp +++ b/PortCore.cpp @@ -22,7 +22,7 @@ //--------------------------------------------------------------------------- -CPortCore::CPortCore( const char * PortName, const int PortInBufLen ) : InBufLen( PortInBufLen ) +CPortCore::CPortCore( const char * PortName, const int PortInBufSize ) { // Port File Handle Handle = -1; @@ -37,14 +37,19 @@ CPortCore::CPortCore( const char * PortName, const int PortInBufLen ) : InBufLen } // In buffer - InBuffer = (char *)malloc( InBufLen ); - InLen = 0; - BytesRead = 0; + Buffer = new CBuffer( PortInBufSize ); - // In buffer Timer + // Input Timeout InStart.tv_sec = 0; InStart.tv_usec = 0; InTimeout = 100; // millisecs + + // Input Markers + InMarkers = NULL; + InMarkerLen = 0; + + // Output + OutputHandle = -1; } //--------------------------------------------------------------------------- @@ -54,6 +59,10 @@ CPortCore::~CPortCore() if (Name) { free( Name ); } + + if (Buffer) { + delete Buffer; + } } //--------------------------------------------------------------------------- @@ -107,8 +116,33 @@ bool CPortCore::Close() } //--------------------------------------------------------------------------- +// Configure general input options +bool CPortCore::InputConfig( const long InputTimeout, const char * InputMarkers, int InputMarkerLen ) +{ + InTimeout = InputTimeout; + if (InputMarkerLen && InputMarkers) { + InMarkerLen = InputMarkerLen; + InMarkers = (char *)malloc( InMarkerLen ); + memcpy( InMarkers, InputMarkers, InMarkerLen ); + } + else { + InMarkerLen = 0; + InputMarkers = NULL; + } + return true; +} +//--------------------------------------------------------------------------- + +// Configure output options +bool CPortCore::OutputConfig( int PortOutputHandle ) +{ + OutputHandle = PortOutputHandle; + return true; +} +//--------------------------------------------------------------------------- + // Set serial port configuration parameters -bool CPortCore::Config( int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ) +bool CPortCore::SerialConfig( int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ) { struct termios newtio; int flags = 0; @@ -246,51 +280,77 @@ bool CPortCore::Config( int Baud, short DataBits, short StopBits, short Parity, } //--------------------------------------------------------------------------- -bool CPortCore::Read() +bool CPortCore::Read( const int MaxRead ) { - // Handle read event - BytesRead = read( Handle, &InBuffer[InLen], InBufLen-InLen ); - if (BytesRead > 0) - { - // Process Reply - InLen += BytesRead; + int BytesRead = 0; - // Reset timer - SetStartTime( &InStart ); + // Read File directly into buffer + if (!(BytesRead = Buffer->ReadFD( Handle ))) + return false; + + // Process Buffer + ProcessBuffer( false ); + + // Reset timer + SetStartTime( &InStart ); + + return true; +} +//--------------------------------------------------------------------------- + +bool CPortCore::ProcessBuffer( bool Force ) +{ + int Pos = 0; + int Len = 0; + char * Data = NULL; + + // Check if buffered data + if (!Buffer->Len()) { + return false; + } + + // Check if forced processed + if (Force) + { + // Show Packet + Len = Buffer->Get( &Data ); + ShowOutput( "Port In", OUT_NORMAL, Data, Len ); + + // Write buffer to Port + Buffer->WriteFD( OutputHandle, Len ); + } + else + { + // Search for end of packet marker + while (Buffer->FindChar( '\n', Pos )) + { + // Show Packet + Len = Buffer->Get( &Data, Pos+1 ); + ShowOutput( "Port In", OUT_NORMAL, Data, Len ); + + // Write buffer to Port + Buffer->WriteFD( OutputHandle, Len ); + } } return true; } //--------------------------------------------------------------------------- -bool CPortCore::Maintain( int SocketHandle ) +bool CPortCore::Maintain() { // Misc long Duration = 0; - int BytesWritten = 0; - int StartWrite = 0; - if (InLen > 0) + if (Buffer->Len() > 0) { // Check duration since last PortIn Duration = TimePassed( InStart ); if (Duration > InTimeout) { - // Handle buffer as packet - InBuffer[ InLen ] = 0; - ShowOutput( "Port In", OUT_NORMAL|OUT_HEX, InBuffer, InLen ); + // Process Input + ProcessBuffer( true ); - // Write output to Port - BytesWritten = 0; - StartWrite = 0; - if (SocketHandle != -1) { - while (StartWrite < InLen) { - BytesWritten = write( SocketHandle, &InBuffer[StartWrite], InLen ); - StartWrite += BytesWritten; - } - } - - // Reset buffer and timer - InLen = 0; + // Reset timer SetInterval( &InStart, 0 ); } } diff --git a/PortCore.h b/PortCore.h index ddd09b3..e6b8c51 100644 --- a/PortCore.h +++ b/PortCore.h @@ -9,7 +9,7 @@ #define REDACORE_PORTCORE_H_ // redA Libraries -/* none */ +#include "BufferCore.h" // Standard C/C++ Libraries #include @@ -36,27 +36,34 @@ private: int Handle; char * Name; - // PortIn buffer - char * InBuffer; - int InBufLen; - int InLen; - int BytesRead; + // Port Buffer + CBuffer * Buffer; - // PortIn Timer - timeval InStart; - long InTimeout; // millisecs + // Input Timer + timeval InStart; + long InTimeout; // millisecs + + // Input Markers + char * InMarkers; + int InMarkerLen; + + // Output + int OutputHandle; public: - CPortCore( const char * PortName, const int PortInBufLen ); + CPortCore( const char * PortName, const int PortInBufSize ); ~CPortCore(); bool Open(); bool Close(); - bool Config( int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ); + bool InputConfig( long InputTimeout, const char * InputMarkers, int InputMarkerLen ); + bool SerialConfig( int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait ); + bool OutputConfig( int PortOutputHandle ); int GetHandle() { return Handle; }; - bool Read(); - bool Maintain( int SocketHandle ); + bool Read( int MaxRead ); + bool Maintain(); + bool ProcessBuffer( bool Force ); }; //---------------------------------------------------------------------------