Important Update:

- Still testing
- Separate Rolling Buffer from PortCore to BufferCore
- Implement BufferCore in PortCore
- Add additional Rolling Buffer functions for future
This commit is contained in:
Charl Wentzel
2016-05-18 15:09:02 +02:00
parent f987ea2224
commit c50766021a
5 changed files with 508 additions and 48 deletions

329
BufferCore.cpp Normal file
View File

@@ -0,0 +1,329 @@
/*
* BufferCore.cpp
*
* Created on: 18 May 2016
* Author: wentzelc
*/
// redA Libraries
#include "BufferCore.h"
// Standard C/C++ Libraries
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
//---------------------------------------------------------------------------
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;
}
//---------------------------------------------------------------------------

64
BufferCore.h Normal file
View File

@@ -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_ */

View File

@@ -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)

View File

@@ -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;
// 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 );
}
}

View File

@@ -9,7 +9,7 @@
#define REDACORE_PORTCORE_H_
// redA Libraries
/* none */
#include "BufferCore.h"
// Standard C/C++ Libraries
#include <sys/time.h>
@@ -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
// 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 );
};
//---------------------------------------------------------------------------