Files
redAcore/SelectableCore.cpp
Charl Wentzel dcfbd85efa Major Update:
- Merged SelectCore and PortCore into new SelectableCore
  Single well integrated Class
- Rename SelectCore.h to SelectableCore.h
- Create new TFileHandle structure for Ports/Sockets
- Moved buffer and Input Timeout from FunctionCore to TFileHandle
- Moved Read, Write and ProcessBuffer from FunctionCore to TFileHandle
Bug Fixes:
- malloc correct size for names
- Calculate MaxFD correctly when closing FDs
2016-05-23 14:35:15 +02:00

925 lines
26 KiB
C++

/*
* CSelectableCore.cpp
*
* Created on: 20 May 2016
* Author: wentzelc
*/
// redA Libraries
#include "SelectableCore.h"
#include "TimingCore.h"
#include "LogCore.h"
// Standard C/C++ Libraries
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
//---------------------------------------------------------------------------
CSelectableCore::CSelectableCore( const char * Name ) :
CFunctionCore( Name )
{
// Handles
FirstHandle = NULL;
}
//---------------------------------------------------------------------------
CSelectableCore::~CSelectableCore()
{
THandle * NextHandle = NULL;
// Destroy File Handles
while (FirstHandle) {
NextHandle = FirstHandle->Next;
DestroyHandle( FirstHandle );
FirstHandle = NextHandle;
}
}
//---------------------------------------------------------------------------
THandle * CSelectableCore::CreateHandle( const char * HandleName )
{
THandle ** Handle = NULL;
// Find Handle by Name or get end of list
Handle = &FirstHandle;
while ( *Handle && strcmp( HandleName, (*Handle)->Name ))
Handle = &((*Handle)->Next);
// Create if necessary
if (!*Handle)
{
// Create File handle at end of list
*Handle = (THandle*)malloc( sizeof(THandle) );
memset( *Handle, 0, sizeof(THandle) );
// Set name
if (HandleName) {
(*Handle)->Name = (char*)malloc( strlen(HandleName)+1 );
strcpy( (*Handle)->Name, HandleName );
}
// Set File Descriptor
(*Handle)->FD = -1;
}
return *Handle;
}
//---------------------------------------------------------------------------
bool CSelectableCore::RemoveHandle( THandle * Handle )
{
THandle ** HandlePtr = NULL;
// Validate
if (!Handle || (Handle->Type != ctRemoteClient)) {
return false;
}
// Find in List
HandlePtr = &FirstHandle;
while (*HandlePtr && (*HandlePtr != Handle)) {
HandlePtr = &((*HandlePtr)->Next);
}
// Remove from list if found
if (*HandlePtr) {
*HandlePtr = (*HandlePtr)->Next;
}
// Destroy Child handle
DestroyHandle( Handle );
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::DestroyHandle( THandle * Handle )
{
// Validate Handle
if (!Handle)
return false;
// Clear parameters
if (Handle->Name)
free( Handle->Name );
if (Handle->FileName)
free( Handle->FileName );
if (Handle->Address)
free( Handle->Address );
// Destroy Buffers
if (Handle->InBuffer)
delete Handle->InBuffer;
if (Handle->OutBuffer)
delete Handle->OutBuffer;
// Clear Input Markers
if (Handle->InMarker)
free( Handle->InMarker );
// Destroy Pointer
free( Handle );
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::SetPortHandle( const char * HandleName, const char * FileName )
{
THandle * Handle = NULL;
// Validate
if (!FileName) {
return false;
}
// Search for file handle
if (!(Handle = GetHandle( HandleName ))) {
return false;
}
// Set Type
Handle->Type = ctPort;
// Clear File Name
if (Handle->FileName) {
free( Handle->FileName );
}
// Set name
Handle->FileName = (char*)malloc( strlen(FileName)+1 );
strcpy( Handle->FileName, FileName );
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::SetSocketHandle( const char * HandleName, EConnectType Type, const char * Address, const int PortNo, bool KeepAlive )
{
THandle * Handle = NULL;
// Validate
if (!Address || (Type == ctNone)) {
return false;
}
// Search for file handle
if (!(Handle = GetHandle( HandleName ))) {
return false;
}
// Clear File Name
if (Handle->FileName) {
free( Handle->FileName );
}
// Set Type
Handle->Type = Type;
Handle->KeepAlive = KeepAlive;
// Clear Address
if (Handle->Address) {
free( Handle->Address );
}
// Set Address & Port
Handle->Address = (char*)malloc( strlen(Address)+1 );
strcpy( Handle->Address, Address );
Handle->PortNo = PortNo;
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::ClearHandle( const char * HandleName )
{
THandle * Handle = NULL;
// Search for file handle
if (!(Handle = GetHandle( HandleName ))) {
return false;
}
// Clear File Name
if (Handle->FileName) {
free( Handle->FileName );
}
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::SetBuffers( const char * HandleName, int InBufSize, int OutBufSize, int InTimeout, const char * InMarker, int InMarkerLen )
{
THandle * Handle = NULL;
// Validate
if (!HandleName) {
return false;
}
// Get Handle
if (!(Handle = GetHandle( HandleName ))) {
return false;;
}
// Input Buffer
if (Handle->InBuffer) {
delete Handle->InBuffer;
Handle->InBuffer = NULL;
}
if (InBufSize) {
Handle->InBuffer = new CBuffer( InBufSize );
}
// Output Buffer
if (Handle->OutBuffer) {
delete Handle->OutBuffer;
Handle->OutBuffer = NULL;
}
if (OutBufSize) {
Handle->OutBuffer = new CBuffer( OutBufSize );
}
// Set Input Timeout
Handle->InTimeout = InTimeout;
// Set Input Markers
if (InMarkerLen && InMarker) {
Handle->InMarkerLen = InMarkerLen;
Handle->InMarker = (char *)malloc( InMarkerLen+1 );
memcpy( Handle->InMarker, InMarker, InMarkerLen );
Handle->InMarker[InMarkerLen] = 0;
}
return true;
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenPort( THandle * Handle )
{
// Validate
if (!Handle || (Handle->Type == ctNone)) {
return -1;
} else if (Handle->State == csOpen) {
return Handle->FD;
}
// Check if port exits
if (access( Handle->FileName, F_OK ) != 0)
{
printf( "Port: %s -> Could not find port\n", Handle->FileName );
return -1;
}
// Open Port
Handle->FD = open( Handle->FileName, O_RDWR );
if (Handle->FD == -1)
{
printf( "Port: %s -> Could not open port\n", Handle->FileName );
return -1;
}
// Confirm open
printf( "Port: %s -> Port opened\n", Handle->Name );
return Handle->FD;
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenServerSocket( THandle * Handle )
{
socklen_t addr_len;
struct sockaddr_in address;
// Socket options
struct linger ServerLinger_opt;
ServerLinger_opt.l_onoff = 1;
ServerLinger_opt.l_linger = 5;
int Reuse_opt = 1;
int KeepAlive_opt = 1;
int TCPidle_opt = 60;
int TCPint_opt = 15;
int TCPcnt_opt = 3;
// Validate Handle
if (Handle->Type != ctServer) {
return false;
}
// Create address
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(Handle->Address);
address.sin_port = htons(Handle->PortNo);
addr_len = sizeof(address);
// Create socket
if ((Handle->FD = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf( "Server Socket: %s [%d] -> Failed to create server socket (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) );
Handle->State = csFailed;
return -1;
};
// Configure connection
if ((setsockopt( Handle->FD, SOL_SOCKET, SO_LINGER, &ServerLinger_opt, sizeof(ServerLinger_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_SOCKET, SO_REUSEADDR, &Reuse_opt, sizeof(Reuse_opt)) == -1))
{
printf( "Server Socket: %s [%d] -> Could not set socket options (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) );
Handle->State = csFailed;
return -1;
}
// Configure TCP keep alive settings
if (Handle->KeepAlive &&
((setsockopt( Handle->FD, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) ))
{
printf( "Server Socket: %s [%d] -> Could not set socket keepalive options (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) );
Handle->State = csFailed;
return -1;
}
// Bind socket
if (bind( Handle->FD, (struct sockaddr *)&address, addr_len ) < 0)
{
printf( "Server Socket: %s [%d] -> Failed to bind server to socket (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) );
close( Handle->FD );
Handle->State = csFailed;
return -1;
};
// Create que for 5 connections
if (listen( Handle->FD, 5 ) < 0)
{
printf( "Server Socket: %s [%d] -> Failed to create server socket listen que (%s)\n", Handle->Address, Handle->PortNo, strerror(errno) );
close( Handle->FD );
Handle->State = csFailed;
return -1;
};
// Server open
Handle->State = csOpen;
printf( "Server Socket: %s [%d] -> Socket binded and listening\n", Handle->Address, Handle->PortNo );
return Handle->FD;
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenRemoteClientSocket( THandle * Handle )
{
THandle ** RemoteClient;
int ClientFD;
char ClientAddress[25];
socklen_t addr_len;
struct sockaddr_in address;
// Validate
if (!Handle) {
return false;
}
// Check Handle type
if (Handle->Type == ctServer)
{
// Accept connection on current socket
addr_len = sizeof( address );
if ((ClientFD = accept( Handle->FD, (struct sockaddr *)&address, &addr_len)) == -1)
{
if (errno == EWOULDBLOCK)
printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", (*RemoteClient)->Address, strerror(errno) );
else
printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", (*RemoteClient)->Address, strerror(errno) );
close( ClientFD );
return -1;
}
// Return client address
strcpy( ClientAddress, inet_ntoa(address.sin_addr) );
// Get end of client list
RemoteClient = &FirstHandle;
while (*RemoteClient) {
RemoteClient = &((*RemoteClient)->Next);
}
// Create Remote Client Handle
*RemoteClient = CreateHandle( "Client" );
SetSocketHandle( "Client", ctRemoteClient, ClientAddress, 0, Handle->KeepAlive );
SetBuffers( "Client", 20, 0, 50, "\n", 1 );
(*RemoteClient)->FD = ClientFD;
(*RemoteClient)->Parent = Handle;
(*RemoteClient)->State = csOpen;
printf( "Remote Socket: %s -> Server accepted connection from client (%s)\n", Handle->Address, ClientAddress );
return (*RemoteClient)->FD;
}
else if (Handle->Type == ctRemoteClient)
{
if (Handle->State == csWaitingtoOpen)
{
// Clear non blocking flag
int flags = fcntl( Handle->FD, F_GETFL, 0 );
fcntl( Handle->FD, F_SETFL, (!O_NONBLOCK)&flags );
// Set new state
Handle->State = csOpen;
// Log event
printf( "Socket: %s -> Client now connected to server (%s)\n", Handle->Address, Handle->Parent->Address );
}
return Handle->FD;
}
return -1;
}
//---------------------------------------------------------------------------
int CSelectableCore::OpenClientSocket( THandle * Handle )
{
socklen_t addr_len;
struct sockaddr_in address;
// Socket options
int KeepAlive_opt = 1;
int TCPidle_opt = 5;
int TCPcnt_opt = 3;
int TCPint_opt = 2;
// Create File descriptor
if ((Handle->FD = socket( AF_INET, SOCK_STREAM, 0 )) < 0)
{
printf( "Client Socket: %s [*] -> Failed to create Client Socket (%s)\n", Handle->Address, strerror(errno) );
return -1;
};
// Set Non blocking open
int flags = fcntl( Handle->FD, F_GETFL, 0 );
fcntl( Handle->FD, F_SETFL, O_NONBLOCK|flags );
// Configure TCP keep alive settings
if (Handle->KeepAlive &&
((setsockopt( Handle->FD, SOL_SOCKET, SO_KEEPALIVE, &KeepAlive_opt, sizeof(KeepAlive_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPIDLE, &TCPidle_opt, sizeof(TCPidle_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPCNT, &TCPcnt_opt, sizeof(TCPcnt_opt)) == -1) ||
(setsockopt( Handle->FD, SOL_TCP, TCP_KEEPINTVL, &TCPint_opt, sizeof(TCPint_opt)) == -1) ))
{
printf( "Client Socket: %s -> Could not set socket keepalive options (%s)\n", Handle->Address, strerror(errno) );
return -1;
}
// Declare address
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr( Handle->Address );
address.sin_port = htons( Handle->PortNo );
addr_len = sizeof(address);
if (!connect( Handle->FD, (struct sockaddr *)&address, addr_len ))
{
// Set status
Handle->State = csOpen;
return Handle->FD;
}
else if (errno == EINPROGRESS)
{
// Set status
Handle->State = csWaitingtoOpen;
return Handle->FD;
}
else
{
printf( "Client Socket: %s -> Client failed to connect (%s)\n", Handle->Address, strerror(errno) );
// Set status
Handle->State = csFailed;
// Close socket
close( Handle->FD );
return -1;
}
}
//---------------------------------------------------------------------------
int CSelectableCore::Open( const char * HandleName )
{
THandle * Handle = NULL;
// Validate
if (!HandleName || !(Handle = GetHandle( HandleName ))) {
return false;
}
// Open correctly
switch (Handle->Type) {
case ctPort :
return OpenPort( Handle );
case ctServer :
return OpenServerSocket( Handle );
case ctClient :
return OpenClientSocket( Handle );
case ctRemoteClient :
return OpenRemoteClientSocket( Handle );
default:
return -1;
}
};
//---------------------------------------------------------------------------
// Delete socket
bool CSelectableCore::Close( THandle * Handle, bool CloseChildren )
{
bool Fail;
THandle * ChildHandle = NULL;
THandle * NextHandle = NULL;
// Close Children
if (CloseChildren && (Handle->Type == ctServer)) {
ChildHandle = FirstHandle;
while (ChildHandle) {
if (ChildHandle->Parent == Handle) {
NextHandle = ChildHandle->Next;
// Close and Destroy handle
Close( ChildHandle );
RemoveHandle( ChildHandle );
// Next Handle
ChildHandle = NextHandle;
} else {
// Next Handle
ChildHandle = ChildHandle->Next;
}
}
}
// Close Handle
Fail = (close( Handle->FD ))? true : false;
Handle->State = ((Fail)? csFailed : csClosed);
Handle->FD = ((Fail)? Handle->FD : -1);
// Show action
switch (Handle->Type)
{
case ctPort:
printf( "Port: %s -> Port %s\n", Handle->FileName, ((Fail)? "failed" : "closed") );
break;
case ctServer:
printf( "Server Socket: %s -> Server %s\n", Handle->Address, ((Fail)? "failed" : "closed") );
break;
case ctRemoteClient:
printf( "Remote Client: %s -> Connection to client %s\n", Handle->Address, ((Fail)? "failed" : "closed") );
break;
case ctClient:
printf( "Client Socket: %s -> Connection to server %s\n", Handle->Address, ((Fail)? "failed" : "closed") );
break;
case ctNone:
default:
printf( "Socket : %s -> Cannot %s socket (invalid socket type)\n", Handle->Address, ((Fail)? "fail" : "close") );
break;
};
return true;
}
//---------------------------------------------------------------------------
// Device Interface
bool CSelectableCore::Read( THandle * Handle )
{
int BytesRead = 0;
int BytesWaiting = 0;
// Validate
if (!Handle) {
return false;
}
// Check for closing event on Socket
if ((Handle->Type == ctRemoteClient) || (Handle->Type == ctClient))
{
// Check if anything to read
ioctl( Handle->FD, FIONREAD, &BytesWaiting );
if (!BytesWaiting) {
// EOF from server (close connection)
Close( Handle );
RemoveHandle( Handle );
return false;
}
// Check if socket ready (non-block open not in progress)
else if (Handle->State == csWaitingtoOpen) {
printf( "Socket: %s -> Cannot read from socket in waiting\n", Name );
return false;
}
}
// Validate
if (Handle->State != csOpen) {
return false;
}
// Read File directly into buffer
if (!(BytesRead = Handle->InBuffer->ReadFromFD( Handle->FD )))
return false;
// Process Buffer
ProcessBuffer( Handle, false );
// Reset timer
SetStartTime( &(Handle->InStart) );
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::Write( THandle * Handle )
{
// Validate
if (!Handle || (Handle->State != csOpen)) {
return false;
}
return true;
}
//---------------------------------------------------------------------------
bool CSelectableCore::Process()
{
THandle * Handle = NULL;
long Duration = 0;
// Check all Input buffers
Handle = FirstHandle;
while (Handle)
{
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0))
{
// Check duration since last PortIn
Duration = TimePassed( Handle->InStart );
if (Duration > Handle->InTimeout)
{
// Process Input
ProcessBuffer( Handle, true );
// Reset timer
SetInterval( &(Handle->InStart), 0 );
}
}
Handle = Handle->Next;
}
return true;
}
//---------------------------------------------------------------------------
int CSelectableCore::WriteToFD( int FD, const char * Data, int Len )
{
int BytesWritten = 0;
int TotalWritten = 0;
int DataRemain = 0;
// Check if buffer created
if ((FD == -1) || !Data) {
return 0;
}
// Read Data into buffer
DataRemain = (Len == -1)? strlen(Data) : Len;
while (DataRemain)
{
// Read from file descriptor
BytesWritten = write( FD, Data, DataRemain );
if (BytesWritten <= 0)
break;
// Update Data Pointers
TotalWritten += BytesWritten;
DataRemain -= BytesWritten;
}
return TotalWritten;
}
//---------------------------------------------------------------------------
int CSelectableCore::Input( int FD, const char * Data, int Len )
{
THandle * Handle = NULL;
int BytesWritten = 0;
// Get File handle
if ((Handle = GetHandle( FD ))) {
// Write to handle
BytesWritten = WriteToFD( Handle->FD, Data, Len );
}
return BytesWritten;
}
//---------------------------------------------------------------------------
bool CSelectableCore::ProcessBuffer( THandle * Handle, bool Force )
{
int Pos = 0;
int Len = 0;
char * Data = NULL;
// Check if buffered data
if (!Handle || !Handle->InBuffer->Len()) {
return false;
}
// Check if forced processed
if (Force)
{
// Show Packet
Len = Handle->InBuffer->Peek( &Data );
ShowOutput( "Port In", OUT_NORMAL, Data, Len );
// Write buffer to Port
if (OutFunction)
OutFunction->Input( 0, Data, Len );
// Clear processed bytes from buffer
Handle->InBuffer->Clear( Len );
}
else
{
// Search for end of packet marker
while (Handle->InBuffer->FindChar( '\n', Pos ))
{
// Show Packet
Len = Handle->InBuffer->Peek( &Data, 0, Pos+1 );
ShowOutput( "Port In", OUT_NORMAL, Data, Len );
// Write buffer to Port
if (OutFunction)
OutFunction->Input( 0, Data, Len );
// Clear processed bytes from buffer
Handle->InBuffer->Clear( Len );
}
}
return true;
}
//---------------------------------------------------------------------------
// Set serial port configuration parameters
bool CSelectableCore::SerialConfig( const char *PortName, int Baud, short DataBits, short StopBits, short Parity, short FlowCtrl, int Wait )
{
THandle * Handle = NULL;
struct termios newtio;
int flags = 0;
speed_t _baud = 0;
int mcs = 0;
// Get Handle
if (!(Handle = GetHandle( PortName ))) {
return false;
}
else if (Handle->Type != ctPort) {
return false;
}
// Flush Data from port
tcflush( Handle->FD, TCIFLUSH );
// Set Open flags
flags = fcntl( Handle->FD, F_GETFL, 0 );
fcntl( Handle->FD, F_SETFL, flags & ~O_NDELAY );
// Read options
if (tcgetattr( Handle->FD, &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->FD, TCIFLUSH);
if (tcsetattr( Handle->FD, TCSANOW, &newtio)!=0)
return false;
// Set Terminal options
ioctl( Handle->FD, TIOCMGET, &mcs);
mcs |= TIOCM_RTS;
ioctl( Handle->FD, TIOCMSET, &mcs);
// Get Options (again)
if (tcgetattr( Handle->FD, &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->FD, 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;
}
//---------------------------------------------------------------------------