embedded-framework/utils/UartDevice/src/UartDeviceImpl.cpp
2024-01-29 12:48:41 -08:00

278 lines
8.2 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 <thread>
#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 writeLength = 0;
if (nullptr == buff) {
LogError("data buff is nullptr.\n");
return SEND_FAILED;
}
if (mFd <= 0) {
LogError("open uart failed.\n");
return SEND_FAILED;
}
size_t writeTotal = 0;
while (writeTotal < buffLength) {
writeLength = fx_write(mFd, buff, buffLength - writeTotal);
writeTotal += writeLength;
}
if (writeTotal == buffLength) {
return writeTotal;
}
tcflush(mFd, TCOFLUSH);
return writeTotal;
}
const size_t UartDeviceImpl::UartRecv(char *buff, const size_t &buffLength, const unsigned int &timeOutMs,
const unsigned int delayReadMs)
{
constexpr int RECV_FAILED = -1;
int readLength = 0;
int fs_sel = -1;
fd_set fs_read;
struct timeval time;
if (nullptr == buff) {
LogError("data buff is nullptr.\n");
return RECV_FAILED;
}
if (mFd <= 0) {
LogError("open uart failed.\n");
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 = fx_select(mFd + 1, &fs_read, NULL, NULL, &time);
if (fs_sel) {
std::this_thread::sleep_for(std::chrono::milliseconds(delayReadMs));
readLength = fx_read(mFd, buff, buffLength);
return readLength;
}
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");
}
}
// static const char *test = "zhanqu";
UartDevice *NewUartDeviceImpl(const UartInfo &uartInfo)
{
if (nullptr == uartInfo.mDevice) {
LogError("Parament error, nullptr == uartInfo.mDevice\n");
return nullptr;
}
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));
}