blob: 7d815ebf8496b2096fef1dce829c668b28503152 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2017 ACIN, fortiss GmbH
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alois Zoitl - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "posixsercommlayer.h"
#include "../devlog.h"
#include "../../core/cominfra/commfb.h"
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sockhand.h>
#include <criticalregion.h>
CPosixSerCommLayer::CPosixSerCommLayer(forte::com_infra::CComLayer* paUpperLayer, forte::com_infra::CBaseCommFB* paFB) :
CSerialComLayerBase(paUpperLayer, paFB){
}
CPosixSerCommLayer::~CPosixSerCommLayer(){
closeConnection();
}
forte::com_infra::EComResponse CPosixSerCommLayer::sendData(void *paData, unsigned int paSize){
if(CFDSelectHandler::scmInvalidFileDescriptor != getSerialHandler()){
ssize_t nToSend = paSize;
while(0 < nToSend){
ssize_t nSentBytes = write(getSerialHandler(), paData, nToSend);
if(nSentBytes <= 0){
DEVLOG_ERROR("CSerCommLayer: Send failed: %s\n", strerror(errno));
return forte::com_infra::e_ProcessDataSendFailed;
}
nToSend -= nSentBytes;
paData = static_cast<char*>(paData) + nSentBytes;
}
}
return forte::com_infra::e_ProcessDataOk;
}
forte::com_infra::EComResponse CPosixSerCommLayer::recvData(const void *, unsigned int){
CCriticalRegion lock(mRecvLock);
ssize_t nReadCount = read(getSerialHandler(), &mRecvBuffer[mBufFillSize], cg_unIPLayerRecvBufferSize - mBufFillSize);
switch (nReadCount){
case 0:
DEVLOG_INFO("Connection closed by peer\n");
mInterruptResp = forte::com_infra::e_InitTerminated;
closeConnection();
break;
case -1:
DEVLOG_ERROR("CSerCommLayer: read failed: %s\n", strerror(errno));
mInterruptResp = forte::com_infra::e_ProcessDataRecvFaild;
break;
default:
//we successfully received data
mBufFillSize += nReadCount;
mInterruptResp = forte::com_infra::e_ProcessDataOk;
break;
}
m_poFb->interruptCommFB(this);
return mInterruptResp;
}
forte::com_infra::EComResponse CPosixSerCommLayer::openSerialConnection(const SSerialParameters& paSerialParameters, CSerialComLayerBase<FORTE_SOCKET_TYPE, FORTE_INVALID_SOCKET>::TSerialHandleType* paHandleResult){
forte::com_infra::EComResponse eRetVal = forte::com_infra::e_ProcessDataNoSocket;
//as first shot take the serial interface device as param (e.g., /dev/ttyS0 )
CFDSelectHandler::TFileDescriptor fileDescriptor = open(paSerialParameters.interfaceName.getValue(), O_RDWR | O_NOCTTY);
if(CFDSelectHandler::scmInvalidFileDescriptor != fileDescriptor){
tcgetattr(fileDescriptor, &mOldTIO);
struct termios stNewTIO;
memset(&stNewTIO, 0, sizeof(stNewTIO));
stNewTIO.c_line = mOldTIO.c_line;
switch (paSerialParameters.baudRate) {
case e50: stNewTIO.c_cflag |= B50; break;
case e75: stNewTIO.c_cflag |= B75; break;
case e110: stNewTIO.c_cflag |= B110; break;
case e134C5: stNewTIO.c_cflag |= B134; break;
case e150: stNewTIO.c_cflag |= B150; break;
case e200: stNewTIO.c_cflag |= B200; break;
case e300: stNewTIO.c_cflag |= B300; break;
case e600: stNewTIO.c_cflag |= B600; break;
case e1200: stNewTIO.c_cflag |= B1200; break;
case e1800: stNewTIO.c_cflag |= B1800; break;
case e2400: stNewTIO.c_cflag |= B2400; break;
case e4800: stNewTIO.c_cflag |= B4800; break;
case e9600: stNewTIO.c_cflag |= B9600; break;
case e19200: stNewTIO.c_cflag |= B19200; break;
case e38400: stNewTIO.c_cflag |= B38400; break;
case e57600: stNewTIO.c_cflag |= B57600; break;
case e115200: stNewTIO.c_cflag |= B115200; break;
case e1000000: stNewTIO.c_cflag |= B1000000; break;
default: return forte::com_infra::e_InitInvalidId; break;
}
stNewTIO.c_ispeed = mOldTIO.c_ispeed;
stNewTIO.c_ospeed = mOldTIO.c_ospeed;
switch (paSerialParameters.byteSize) {
case e5: stNewTIO.c_cflag |= CS5; break;
case e6: stNewTIO.c_cflag |= CS6; break;
case e7: stNewTIO.c_cflag |= CS7; break;
case e8: stNewTIO.c_cflag |= CS8; break;
default: return forte::com_infra::e_InitInvalidId; break;
}
switch(paSerialParameters.stopBits){
case eOneBit: stNewTIO.c_cflag &= ~CSTOPB; break;
case eTwoBits: stNewTIO.c_cflag |= CSTOPB; break;
default: return forte::com_infra::e_InitInvalidId; break;
}
switch(paSerialParameters.parity){
case eNoParity:
stNewTIO.c_cflag &= ~(PARENB | PARODD | CMSPAR);
break;
case eODD: stNewTIO.c_cflag |= PARENB | PARODD; break;
case eEven:
stNewTIO.c_cflag |= PARENB;
stNewTIO.c_cflag &= ~PARODD;
break;
default: return forte::com_infra::e_InitInvalidId; break;
}
stNewTIO.c_cflag &= ~CRTSCTS; // no hardware flow control
stNewTIO.c_cflag |= (CLOCAL | CREAD); /* Local line - do not change "owner" of port | Enable receiver*/
stNewTIO.c_iflag = mOldTIO.c_iflag;
stNewTIO.c_iflag |= IGNPAR; /* Map CR to NL | IGNPAR (was here before) Ignore parity error. TODO: Should we delete this? It was on the old code*/ ;
stNewTIO.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
stNewTIO.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | INPCK | IUCLC); // Disable any special handling of received bytes
stNewTIO.c_oflag = mOldTIO.c_oflag;
stNewTIO.c_oflag &= ~(OPOST | ONLCR | OCRNL);
stNewTIO.c_lflag = mOldTIO.c_lflag;
stNewTIO.c_lflag &= ~(ICANON| ECHO | ECHOE| ECHONL | ECHOK | ISIG | IEXTEN | CRTSCTS);
stNewTIO.c_cc[VINTR] = _POSIX_VDISABLE; /* Ctrl-c */
stNewTIO.c_cc[VQUIT] = _POSIX_VDISABLE; /* Ctrl-\ */
stNewTIO.c_cc[VERASE] = _POSIX_VDISABLE; /* del */
stNewTIO.c_cc[VKILL] = _POSIX_VDISABLE; /* @ */
stNewTIO.c_cc[VEOF] = _POSIX_VDISABLE; /* Ctrl-d */
stNewTIO.c_cc[VTIME] = 10; /* inter-character timer unused */
stNewTIO.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
stNewTIO.c_cc[VSWTC] = _POSIX_VDISABLE; /* '\0' */
stNewTIO.c_cc[VSTART] = _POSIX_VDISABLE; /* Ctrl-q */
stNewTIO.c_cc[VSTOP] = _POSIX_VDISABLE; /* Ctrl-s */
stNewTIO.c_cc[VSUSP] = _POSIX_VDISABLE; /* Ctrl-z */
stNewTIO.c_cc[VEOL] = _POSIX_VDISABLE; /* '\0' */
stNewTIO.c_cc[VREPRINT] = _POSIX_VDISABLE; /* Ctrl-r */
stNewTIO.c_cc[VDISCARD] = _POSIX_VDISABLE; /* Ctrl-u */
stNewTIO.c_cc[VWERASE] = _POSIX_VDISABLE; /* Ctrl-w */
stNewTIO.c_cc[VLNEXT] = _POSIX_VDISABLE; /* Ctrl-v */
stNewTIO.c_cc[VEOL2] = _POSIX_VDISABLE; /* '\0' */
tcflush(fileDescriptor, TCIFLUSH);
tcsetattr(fileDescriptor, TCSANOW, &stNewTIO);
getExtEvHandler<CFDSelectHandler>().addComCallback(fileDescriptor, this);
*paHandleResult = fileDescriptor;
eRetVal = forte::com_infra::e_InitOk;
}
else{
eRetVal = forte::com_infra::e_ProcessDataInvalidObject;
DEVLOG_ERROR("CSerCommLayer: open failed: %s\n", strerror(errno));
}
return eRetVal;
}
void CPosixSerCommLayer::closeConnection(){
CFDSelectHandler::TFileDescriptor fileDescriptor = getSerialHandler();
if(CFDSelectHandler::scmInvalidFileDescriptor != fileDescriptor){
getExtEvHandler<CFDSelectHandler>().removeComCallback(fileDescriptor);
tcsetattr(fileDescriptor, TCSANOW, &mOldTIO);
close(fileDescriptor);
}
}