259 lines
7.6 KiB
C++
259 lines
7.6 KiB
C++
/*
|
|
* Copyright (c) 2023 Fancy Code.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "UartDeviceImpl.h"
|
|
#include "ILog.h"
|
|
#include "LinuxApi.h"
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
constexpr int INVALID_FD = -1;
|
|
static const char *UART_DEVICE_NAME = "uart_device";
|
|
const char *GetUartDeviceModuleName(void) { return UART_DEVICE_NAME; }
|
|
UartDeviceImpl::UartDeviceImpl(const UartInfo &uatrInfo) : mUatrInfo(uatrInfo) { mFd = -1; }
|
|
const StatusCode UartDeviceImpl::UartOpen(void)
|
|
{
|
|
mFd = fx_open(mUatrInfo.mDevice, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
|
if (INVALID_FD == mFd) {
|
|
perror("Can't Open Serial Port");
|
|
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
|
}
|
|
return SetConfig();
|
|
}
|
|
|
|
const size_t UartDeviceImpl::UartSend(const char *buff, const size_t &buffLength)
|
|
{
|
|
constexpr int SEND_FAILED = -1;
|
|
size_t len = 0;
|
|
if (mFd <= 0) {
|
|
LogError("open uart failed.\n");
|
|
return SEND_FAILED;
|
|
}
|
|
// TODO: what if write return less then buffLength?
|
|
len = write(mFd, buff, buffLength);
|
|
if (len == buffLength) {
|
|
return len;
|
|
}
|
|
tcflush(mFd, TCOFLUSH);
|
|
return len;
|
|
}
|
|
const size_t UartDeviceImpl::UartRecv(char *buff, const size_t &buffLength, const unsigned int &timeOutMs,
|
|
const unsigned int delayRead)
|
|
{
|
|
constexpr int RECV_FAILED = -1;
|
|
int len, fs_sel;
|
|
fd_set fs_read;
|
|
struct timeval time;
|
|
|
|
if (mFd <= 0) {
|
|
return RECV_FAILED;
|
|
}
|
|
|
|
FD_ZERO(&fs_read);
|
|
FD_SET(mFd, &fs_read);
|
|
time.tv_sec = timeOutMs / 1000;
|
|
time.tv_usec = (timeOutMs % 1000) * 1000;
|
|
fs_sel = select(mFd + 1, &fs_read, NULL, NULL, &time);
|
|
if (fs_sel) {
|
|
usleep(1000 * delayRead);
|
|
len = read(mFd, buff, buffLength);
|
|
return len;
|
|
}
|
|
return RECV_FAILED;
|
|
}
|
|
void UartDeviceImpl::UartTcflush(void)
|
|
{
|
|
if (mFd > 0) {
|
|
tcflush(mFd, TCIFLUSH);
|
|
}
|
|
}
|
|
const StatusCode UartDeviceImpl::SetConfig(void)
|
|
{
|
|
int i;
|
|
int speed_arr[] = {B1152000,
|
|
B1000000,
|
|
B921600,
|
|
B576000,
|
|
B500000,
|
|
B460800,
|
|
B230400,
|
|
B115200,
|
|
B19200,
|
|
B9600,
|
|
B4800,
|
|
B2400,
|
|
B1200,
|
|
B300};
|
|
int name_arr[] = {
|
|
1152000, 1000000, 921600, 576000, 500000, 460800, 230400, 115200, 19200, 9600, 4800, 2400, 1200, 300};
|
|
struct termios options;
|
|
|
|
if (fx_tcgetattr(mFd, &options) != 0) {
|
|
perror("SetupSerial 1");
|
|
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
|
}
|
|
|
|
// set buater rate
|
|
for (i = 0; i < (int)(sizeof(speed_arr) / sizeof(int)); i++) {
|
|
if (mUatrInfo.mSpeed == name_arr[i]) {
|
|
cfsetispeed(&options, speed_arr[i]);
|
|
cfsetospeed(&options, speed_arr[i]);
|
|
}
|
|
}
|
|
|
|
// set control model
|
|
options.c_cflag |= CLOCAL;
|
|
options.c_cflag |= CREAD;
|
|
|
|
// set flow control
|
|
switch (mUatrInfo.mFlowCtrl) {
|
|
case 0: // none
|
|
options.c_cflag &= ~CRTSCTS;
|
|
break;
|
|
case 1: // use hard ware
|
|
options.c_cflag |= CRTSCTS;
|
|
break;
|
|
case 2: // use sofware
|
|
options.c_cflag |= IXON | IXOFF | IXANY;
|
|
break;
|
|
}
|
|
|
|
// select data bit
|
|
options.c_cflag &= ~CSIZE;
|
|
switch (mUatrInfo.mDataBits) {
|
|
case 5:
|
|
options.c_cflag |= CS5;
|
|
break;
|
|
case 6:
|
|
options.c_cflag |= CS6;
|
|
break;
|
|
case 7:
|
|
options.c_cflag |= CS7;
|
|
break;
|
|
case 8:
|
|
options.c_cflag |= CS8;
|
|
break;
|
|
default:
|
|
LogError("Unsupported data size\n");
|
|
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
|
}
|
|
|
|
// select parity bit
|
|
switch (mUatrInfo.mParity) {
|
|
case 'n':
|
|
case 'N':
|
|
options.c_cflag &= ~PARENB;
|
|
options.c_iflag &= ~INPCK;
|
|
break;
|
|
case 'o':
|
|
case 'O':
|
|
options.c_cflag |= (PARODD | PARENB);
|
|
options.c_iflag |= INPCK;
|
|
break;
|
|
case 'e':
|
|
case 'E':
|
|
options.c_cflag |= PARENB;
|
|
options.c_cflag &= ~PARODD;
|
|
options.c_iflag |= INPCK;
|
|
break;
|
|
case 's':
|
|
case 'S':
|
|
options.c_cflag &= ~PARENB;
|
|
options.c_cflag &= ~CSTOPB;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Unsupported parity\n");
|
|
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
|
}
|
|
// set stopbit
|
|
switch (mUatrInfo.mStopBits) {
|
|
case 1:
|
|
options.c_cflag &= ~CSTOPB;
|
|
break;
|
|
case 2:
|
|
options.c_cflag |= CSTOPB;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Unsupported stop bits\n");
|
|
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
|
}
|
|
|
|
// set raw data output
|
|
options.c_oflag &= ~OPOST;
|
|
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
|
// options.c_lflag &= ~(ISIG | ICANON);
|
|
// set wait time
|
|
options.c_cc[VTIME] = 1;
|
|
options.c_cc[VMIN] = 1;
|
|
tcflush(mFd, TCIFLUSH);
|
|
// set the attribute to HiSerial device
|
|
if (fx_tcsetattr(mFd, TCSANOW, &options) != 0) {
|
|
perror("com set error!\n");
|
|
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
|
}
|
|
return CreateStatusCode(STATUS_CODE_OK);
|
|
}
|
|
const StatusCode (*mOpen)(UartDevice *);
|
|
static const StatusCode UartOpen(UartDevice *object)
|
|
{
|
|
UartDeviceImpl_S *impl = UartDeviceImplConvert(object);
|
|
return impl->mUartImpl->UartOpen();
|
|
}
|
|
static const size_t UartSend(UartDevice *object, const char *buff, const size_t buffLength)
|
|
{
|
|
UartDeviceImpl_S *impl = UartDeviceImplConvert(object);
|
|
return impl->mUartImpl->UartSend(buff, buffLength);
|
|
}
|
|
static const size_t UartRecv(UartDevice *object, char *buff, const size_t buffLength, const unsigned int timeoutMs)
|
|
{
|
|
UartDeviceImpl_S *impl = UartDeviceImplConvert(object);
|
|
constexpr int READ_NOT_DELAY = 0;
|
|
return impl->mUartImpl->UartRecv(buff, buffLength, timeoutMs, READ_NOT_DELAY);
|
|
}
|
|
static void UartTcflush(UartDevice *object)
|
|
{
|
|
UartDeviceImpl_S *impl = UartDeviceImplConvert(object);
|
|
return impl->mUartImpl->UartTcflush();
|
|
}
|
|
static void UartImpllFree(void *ptr)
|
|
{
|
|
UartDeviceImpl_S *object = ((UartDeviceImpl_S *)(((char *)ptr) - sizeof(UartDeviceHeader)));
|
|
if (UART_DEVICE_NAME == object->mHeader.mCheckName) {
|
|
object->mUartImpl = nullptr;
|
|
free(((char *)ptr) - sizeof(UartDeviceHeader));
|
|
}
|
|
else {
|
|
LogError("Unknow ptr.\n");
|
|
}
|
|
}
|
|
UartDevice *NewUartDeviceImpl(const UartInfo &uartInfo)
|
|
{
|
|
LogInfo("Create the uart device object.\n");
|
|
UartDeviceImpl_S *impl = (UartDeviceImpl_S *)malloc(sizeof(UartDeviceImpl_S));
|
|
UartDeviceImpl_S tmp;
|
|
memcpy((void *)impl, (void *)&tmp, sizeof(UartDeviceImpl_S));
|
|
impl->mHeader.mCheckName = UART_DEVICE_NAME;
|
|
impl->mBase.mOpen = UartOpen;
|
|
impl->mBase.mSend = UartSend;
|
|
impl->mBase.mRecv = UartRecv;
|
|
impl->mBase.mTcflush = UartTcflush;
|
|
impl->mBase.mFree = UartImpllFree;
|
|
impl->mUartImpl = std::make_shared<UartDeviceImpl>(uartInfo);
|
|
return (UartDevice *)(((char *)impl) + sizeof(UartDeviceHeader));
|
|
} |