hunting/utils/UartDevice/src/UartDeviceImpl.cpp
2024-01-25 15:38:02 -08:00

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));
}