Files
redAcore/PortCore.cpp
Charl Wentzel 5c7eb956a7 Bug fixes:
- Implement changes from CoreBuffer
- Do not update BufLen in WriteToFD()
2016-05-19 09:46:18 +02:00

371 lines
9.4 KiB
C++

/*
* PortCore.cpp
*
* Created on: 13 May 2016
* Author: wentzelc
*/
// redA Libraries
#include "PortCore.h"
#include "TimingCore.h"
#include "LogCore.h"
// Standard C/C++ Libraries
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
//---------------------------------------------------------------------------
CPortCore::CPortCore( const char * PortName, const int PortInBufSize )
{
// Port File Handle
Handle = -1;
// Copy Port name
if (PortName) {
Name = (char*)malloc( strlen( PortName)+ 1);
strcpy( Name, PortName );
}
else {
Name = NULL;
}
// In buffer
Buffer = new CBuffer( PortInBufSize );
// Input Timeout
InStart.tv_sec = 0;
InStart.tv_usec = 0;
InTimeout = 100; // millisecs
// Input Markers
InMarkers = NULL;
InMarkerLen = 0;
// Output
OutputHandle = -1;
}
//---------------------------------------------------------------------------
CPortCore::~CPortCore()
{
// Destroy pointers
if (Name) {
free( Name );
}
if (Buffer) {
delete Buffer;
}
if (InMarkers) {
free( InMarkers );
}
}
//---------------------------------------------------------------------------
bool CPortCore::Open()
{
// Check if valid port name
if (!Name) {
return false;
}
// Check if port exits
if (access( Name, F_OK ) != 0)
{
printf( "Port: %s -> Could not find port\n", Name );
return false;
}
// Open Port
Handle = open( Name, O_RDWR );
if (Handle == -1)
{
printf( "Port: %s -> Could not open port\n", Name );
return false;
}
// Confirm open
printf( "Port: %s -> Port opened\n", Name );
return true;
}
//---------------------------------------------------------------------------
bool CPortCore::Close()
{
int result;
// Check if valid port
if (Handle == -1) {
return true;
}
// Close port
result = close( Handle );
if (result) {
printf( "Port: %s -> Port not closed properly\n", Name );
return false;
}
// Port closed
printf( "Port: %s -> Port closed\n", Name );
return true;
}
//---------------------------------------------------------------------------
// Configure general input options
bool CPortCore::InputConfig( const long InputTimeout, const char * InputMarkers, int InputMarkerLen )
{
InTimeout = InputTimeout;
if (InputMarkerLen && InputMarkers) {
InMarkerLen = InputMarkerLen;
if (InMarkers) { free( InMarkers ); }
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::SerialConfig( int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait )
{
struct termios newtio;
int flags = 0;
speed_t _baud = 0;
int mcs = 0;
// Flush Data from port
tcflush( Handle, TCIFLUSH );
// Set Open flags
flags = fcntl( Handle, F_GETFL, 0 );
fcntl( Handle, F_SETFL, flags & ~O_NDELAY );
// Read options
if (tcgetattr( Handle, &newtio ) != 0)
return false;
// Process the baud rate
switch (Baud)
{
case 921600: _baud = B921600; break;
case 576000: _baud = B576000; break;
case 460800: _baud = B460800; break;
case 230400: _baud = B230400; break;
//case 128000: _baud = B128000; break;
case 115200: _baud = B115200; break;
//case 76800: _baud = B76800; break;
case 57600: _baud = B57600; break;
case 38400: _baud = B38400; break;
//case 28800: _baud = B28800; break;
case 19200: _baud = B19200; break;
//case 14400: _baud = B14400; break;
case 9600: _baud = B9600; break;
case 4800: _baud = B4800; break;
case 2400: _baud = B2400; break;
case 1800: _baud = B1800; break;
case 1200: _baud = B1200; break;
case 600: _baud = B600; break;
case 300: _baud = B300; break;
case 200: _baud = B200; break;
case 150: _baud = B150; break;
case 134: _baud = B134; break;
case 110: _baud = B110; break;
case 75: _baud = B75; break;
case 50: _baud = B50; break;
default: _baud = B9600; break;
}
// Set Baud rate
cfsetospeed( &newtio, (speed_t)_baud );
cfsetispeed( &newtio, (speed_t)_baud );
// Generate Mark/Space parity
if ((DataBits == 7) && ((Parity == MARK_PARITY) || (Parity == SPACE_PARITY)))
DataBits = 8;
// Process the data bits
newtio.c_cflag &= ~CSIZE;
switch (DataBits)
{
case 5: newtio.c_cflag |= CS5; break;
case 6: newtio.c_cflag |= CS6; break;
case 7: newtio.c_cflag |= CS7; break;
case 8: newtio.c_cflag |= CS8; break;
default: newtio.c_cflag |= CS8; break;
}
// Set other flags
newtio.c_cflag |= CLOCAL | CREAD;
// Process Parity
newtio.c_cflag &= ~(PARENB | PARODD);
if (Parity == EVEN_PARITY)
newtio.c_cflag |= PARENB;
else if (Parity == ODD_PARITY)
newtio.c_cflag |= (PARENB | PARODD);
// Flow Control (for now)
newtio.c_cflag &= ~CRTSCTS;
// Process Stop Bits
if (StopBits == 2)
newtio.c_cflag |= CSTOPB;
else
newtio.c_cflag &= ~CSTOPB;
newtio.c_iflag = IGNBRK;
// Software Flow Control
if (FlowCtrl == SW_FLOWCTRL)
newtio.c_iflag |= IXON | IXOFF;
else
newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
// Set RAW input & output
newtio.c_lflag=0;
newtio.c_oflag=0;
// Set wait parameters
newtio.c_cc[VTIME] = Wait; // Blocking: Allow at least a tenth of a second to wait for data
newtio.c_cc[VMIN] = 0; // Non-blocking: Don't set min bytes to receive
// Set Options (first time)
//tcflush( Handle, TCIFLUSH);
if (tcsetattr( Handle, TCSANOW, &newtio)!=0)
return false;
// Set Terminal options
ioctl( Handle, TIOCMGET, &mcs);
mcs |= TIOCM_RTS;
ioctl( Handle, TIOCMSET, &mcs);
// Get Options (again)
if (tcgetattr( Handle, &newtio) != 0)
return false;
// Process Hardware Flow Control
if (FlowCtrl == HW_FLOWCTRL)
newtio.c_cflag |= CRTSCTS;
else
newtio.c_cflag &= ~CRTSCTS;
// Set Options (second time)
if (tcsetattr( Handle, TCSANOW, &newtio ) != 0)
{
printf( "Port: %s -> Could not configure port\n", Name );
return false;
}
// Port configured
printf( "Port: %s -> Port configured\n", Name );
return true;
}
//---------------------------------------------------------------------------
bool CPortCore::Read( const int MaxRead )
{
int BytesRead = 0;
// Read File directly into buffer
if (!(BytesRead = Buffer->ReadFromFD( 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->Peek( &Data );
ShowOutput( "Port In", OUT_NORMAL, Data, Len );
// Write buffer to Port
Buffer->WriteToFD( OutputHandle, Len );
// Clear processed bytes from buffer
Buffer->Clear( Len );
}
else
{
// Search for end of packet marker
while (Buffer->FindChar( '\n', Pos ))
{
// Show Packet
Len = Buffer->Peek( &Data, 0, Pos+1 );
ShowOutput( "Port In", OUT_NORMAL, Data, Len );
// Write buffer to Port
Buffer->WriteToFD( OutputHandle, Len );
// Clear processed bytes from buffer
Buffer->Clear( Len );
}
}
return true;
}
//---------------------------------------------------------------------------
bool CPortCore::Maintain()
{
// Misc
long Duration = 0;
if (Buffer->Len() > 0)
{
// Check duration since last PortIn
Duration = TimePassed( InStart );
if (Duration > InTimeout)
{
// Process Input
ProcessBuffer( true );
// Reset timer
SetInterval( &InStart, 0 );
}
}
return true;
}
//---------------------------------------------------------------------------