/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include //--------------------------------------------------------------------------- CSelectableCore::CSelectableCore( const char * Name, CSelect * Selector ) : CFunctionCore( Name ) { // Handles FirstHandle = NULL; // Select Select = Selector; } //--------------------------------------------------------------------------- CSelectableCore::~CSelectableCore() { THandle * NextHandle = NULL; // Destroy File Handles while (FirstHandle) { NextHandle = FirstHandle->Next; DestroyHandle( FirstHandle ); FirstHandle = NextHandle; } } //--------------------------------------------------------------------------- THandle * CSelectableCore::CreateHandle( const char * HandleName, bool CreateIO ) { 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; } // Create Matching IO point if (CreateIO) { (*Handle)->LocalIO = AddLocalIO( HandleName ); } return *Handle; } //--------------------------------------------------------------------------- bool CSelectableCore::RemoveHandle( THandle * Handle ) { THandle ** HandlePtr = NULL; // Validate if (!Handle || (Handle->State == csOpen) || (Handle->State == csWaitingtoOpen)) { 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( THandle * Handle, const char * FileName ) { // Validate if (!Handle || (Handle->Type != ctNone) || !FileName) { 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( THandle * Handle, EConnectType Type, const char * Address, const int PortNo, bool KeepAlive ) { // Validate if (!Handle || (Handle->Type != ctNone) || !Address || (Type == ctNone) || (Type == ctPort)) { return false; } // 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( THandle * Handle ) { // Validate if (!Handle) { return false; } // Reset Type related parameters if (Handle->FileName) { free( Handle->FileName ); Handle->FileName = NULL; } if (Handle->Address) { free( Handle->Address ); Handle->Address = NULL; } Handle->PortNo = 0; // Reset Parameters Handle->Type = ctNone; return true; } //--------------------------------------------------------------------------- bool CSelectableCore::SetBuffers( THandle * Handle, int InBufSize, int OutBufSize, int InTimeout, const char * InMarker, int InMarkerLen ) { // Validate if (!Handle) { 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 Handle->State = csOpen; 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; } // Set non-blocking flag int flags = fcntl( Handle->FD, F_GETFL, 0 ); fcntl( Handle->FD, F_SETFL, flags | O_NONBLOCK ); // 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[100]; char ClientName[100]; socklen_t addr_len; struct sockaddr_in address; // Validate if (!Handle) { return -1; } // 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 == EAGAIN) || (errno == EWOULDBLOCK)) printf( "Remote Socket: %s [*] -> Failed to accept blocking connection (%s)\n", Handle->Address, strerror(errno) ); else printf( "Remote Socket: %s [*] -> Failed to accept connection (%s)\n", Handle->Address, strerror(errno) ); return -1; } // Set non-blocking flag int flags = fcntl( ClientFD, F_GETFL, 0 ); fcntl( ClientFD, F_SETFL, flags | O_NONBLOCK ); // 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 sprintf( ClientName, "%s-%d", Handle->Name, ClientFD ); *RemoteClient = CreateHandle( ClientName ); SetSocketHandle( *RemoteClient, ctRemoteClient, ClientAddress, 0, Handle->KeepAlive ); // Copy Parent Buffer setup SetBuffers( *RemoteClient, ((Handle->InBuffer)? Handle->InBuffer->Size() : 0), ((Handle->OutBuffer)? Handle->OutBuffer->Size() : 0), Handle->InTimeout, Handle->InMarker, Handle->InMarkerLen ); // Set Key parameters (*RemoteClient)->FD = ClientFD; (*RemoteClient)->Parent = Handle; (*RemoteClient)->State = csWaitingtoOpen; printf( "Remote Socket: %s -> Server accepted connection from client (%s)\n", Handle->Address, ClientAddress ); return (*RemoteClient)->FD; } else if (Handle->Type == ctRemoteClient) { // Check state if (Handle->State == csOpen) { // Already open return Handle->FD; } else if (Handle->State == csWaitingtoOpen) { // Update state Handle->State = csOpen; 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; // Check state if (Handle->State == csOpen) { // Already open return Handle->FD; } else if (Handle->State == csWaitingtoOpen) { // Update state Handle->State = csOpen; return Handle->FD; } // 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 == EAGAIN) || (errno == EWOULDBLOCK)) { printf( "Client Socket: %s -> Client waiting to connect (%s)\n", Handle->Address, strerror(errno) ); // 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 ) { int FD = -1; THandle * Handle = NULL; // Validate if (!HandleName || !(Handle = GetHandle( HandleName ))) { return false; } // Open correctly switch (Handle->Type) { case ctPort : FD = OpenPort( Handle ); break; case ctServer : FD = OpenServerSocket( Handle ); break; case ctClient : FD = OpenClientSocket( Handle ); break; case ctRemoteClient : FD = OpenRemoteClientSocket( Handle ); break; default: FD = -1; } // Add to Select Lists if (Select && FD != -1) { Select->Add( FD, true, true, this ); } return FD; }; //--------------------------------------------------------------------------- // 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 Close( ChildHandle ); // Next Handle ChildHandle = NextHandle; } else { // Next Handle ChildHandle = ChildHandle->Next; } } } // Remove from Select List if (Select) { Select->Remove( Handle->FD, true, true ); } // 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 ClientFD = -1; int BytesRead = 0; int BytesWaiting = -1; // Validate if (!Handle) { return false; } // Check for closing/opening event on Socket if (Handle->Type == ctServer) { // Incoming client request ClientFD = OpenRemoteClientSocket( Handle ); if (ClientFD != -1) { // Add to Select Lists if (Select) { Select->Add( ClientFD, true, true, this ); } return true; } } else if ((Handle->Type == ctRemoteClient) || (Handle->Type == ctClient)) { // Check if anything to read ioctl( Handle->FD, FIONREAD, &BytesWaiting ); // EOF from server if (!BytesWaiting) { // Close Handle Close( Handle ); // Destroy Remote Client if (Handle->Type == ctRemoteClient) { RemoveHandle( Handle ); } return false; } // Check if socket ready (non-block open 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 ) { int BytesWritten = 0; // Validate if (!Handle) { return false; } if (Handle->State == csWaitingtoOpen) { // Complete socket open process if (Handle->Type == ctRemoteClient) { OpenRemoteClientSocket( Handle ); } else if (Handle->Type == ctClient) { OpenClientSocket( Handle ); } // Remove from set for select write if (Select) { Select->Remove( Handle->FD, false, true ); } return true; } else if (Handle->State == csOpen) { if (Handle->OutBuffer) { // Write to FD directly from buffer if ((BytesWritten = Handle->OutBuffer->WriteToFD( Handle->FD ))) { // Update Buffer Handle->OutBuffer->Clear( BytesWritten ); } // Check if Buffer emtpy if (!Handle->OutBuffer->Len()) { // Add to Select Write list if (Select) { Select->Remove( Handle->FD, false, true ); } } } else { // No Output buffer, so remove from Write list if (Select) { Select->Remove( Handle->FD, false, true ); } } return true; } return false; } //--------------------------------------------------------------------------- bool CSelectableCore::ProcessBuffer( THandle * Handle, bool Force ) { int Pos = 0; int Len = 0; char * Data = NULL; TLocalIO * LocalIO = NULL; TLinkedIO * Output = 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 Outputs if (Handle->Type == ctRemoteClient) { LocalIO = Handle->Parent->LocalIO; } else { LocalIO = Handle->LocalIO; } if (LocalIO) { Output = LocalIO->FirstOutput; while (Output) { Output->Function->Input( Output->IOName, Data, Len ); Output = Output->Next; } } // Clear processed bytes from buffer Handle->InBuffer->Clear( Len ); } else { // Search for end of packet marker while (Handle->InBuffer->FindStr( Handle->InMarker, Handle->InMarkerLen, Pos )) { // Show Packet Len = Handle->InBuffer->Peek( &Data, 0, Pos+1 ); ShowOutput( "Port In", OUT_NORMAL, Data, Len ); // Write buffer to Outputs if (Handle->Type == ctRemoteClient) { LocalIO = Handle->Parent->LocalIO; } else { LocalIO = Handle->LocalIO; } if (LocalIO) { Output = LocalIO->FirstOutput; while (Output) { Output->Function->Input( Output->IOName, Data, Len ); Output = Output->Next; } } // Clear processed bytes from buffer Handle->InBuffer->Clear( Len ); } } return true; } //--------------------------------------------------------------------------- int CSelectableCore::ReadFromFD( int FD, char * Data, int MaxLen ) { int BytesRead = 0; int TotalRead = 0; int DataRemain = 0; // Check if buffer created if ((FD == -1) || !Data) { return 0; } // Read Data into buffer DataRemain = (MaxLen == -1)? strlen(Data) : MaxLen; while (DataRemain) { // Read from file descriptor BytesRead = read( FD, Data, DataRemain ); if (BytesRead <= 0) break; // Update Data Pointers TotalRead += BytesRead; DataRemain -= BytesRead; } return TotalRead; } //--------------------------------------------------------------------------- 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( const char * IOName, const char * Data, int Len ) { THandle * Handle = NULL; THandle * ChildHandle = NULL; int BytesWritten = 0; // Validate if (!IOName || !Data) { return 0; } else if (Len == -1) { Len = strlen( Data ); } // Get File handle if ((Handle = GetHandle( IOName ))) { if (Handle->Type == ctServer) { // Cannot write to server socket, so Update Remote Client connections individually ChildHandle = FirstHandle; while (ChildHandle) { // Check if child if (ChildHandle->Parent == Handle) { // Decide where to put data if (ChildHandle->OutBuffer) { // Write to buffer BytesWritten = ChildHandle->OutBuffer->Push( Data, Len ); // Add to select write list if (BytesWritten) { Select->Add( ChildHandle->FD, false, true, this ); } } else { // Write directly to handle BytesWritten = WriteToFD( ChildHandle->FD, Data, Len ); } } // Next ChildHandle = ChildHandle->Next; } // Cannot verify individually, so assume all bytes was written BytesWritten = Len; } else { // Decide where to put data if (Handle->OutBuffer) { // Write to buffer BytesWritten = Handle->OutBuffer->Push( Data, Len ); // Add to select write list if (BytesWritten) { Select->Add( Handle->FD, false, true, this ); } } else { // Write directly to handle BytesWritten = WriteToFD( Handle->FD, Data, Len ); } } } return BytesWritten; } //--------------------------------------------------------------------------- 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; } //--------------------------------------------------------------------------- // Set serial port configuration parameters bool CSelectableCore::SerialConfig( THandle * Handle, 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; // Get Handle if (!Handle || (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; } //---------------------------------------------------------------------------