mirror of
https://gitee.com/jiuyilian/embedded-framework.git
synced 2025-01-06 10:16:51 -05:00
289 lines
8.5 KiB
C++
289 lines
8.5 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);
|
|
}
|
|
LogInfo("open uart device = %s, fd = %d\n", mUatrInfo.mDevice, mFd);
|
|
return SetConfig();
|
|
}
|
|
|
|
const ssize_t UartDeviceImpl::UartSend(const void *buff, const size_t &buffLength)
|
|
{
|
|
constexpr ssize_t SEND_FAILED = -1;
|
|
ssize_t writeLength = -1;
|
|
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);
|
|
if (SEND_FAILED == writeLength) {
|
|
tcflush(mFd, TCOFLUSH);
|
|
return SEND_FAILED;
|
|
}
|
|
writeTotal += writeLength;
|
|
}
|
|
if (writeTotal == buffLength) {
|
|
return writeTotal;
|
|
}
|
|
tcflush(mFd, TCOFLUSH);
|
|
return writeTotal;
|
|
}
|
|
const ssize_t UartDeviceImpl::UartRecv(void *buff, const size_t &buffLength, const unsigned int &timeOutMs,
|
|
const unsigned int delayReadMs)
|
|
{
|
|
constexpr size_t RECV_FAILED = -1;
|
|
ssize_t readLength = 0;
|
|
int selectResult = -1;
|
|
fd_set fdsRead;
|
|
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(&fdsRead);
|
|
FD_SET(mFd, &fdsRead);
|
|
time.tv_sec = timeOutMs / 1000;
|
|
time.tv_usec = (timeOutMs % 1000) * 1000;
|
|
selectResult = fx_select(mFd + 1, &fdsRead, NULL, NULL, &time);
|
|
if (selectResult) {
|
|
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 ssize_t UartSend(UartDevice *object, const void *buff, const size_t buffLength)
|
|
{
|
|
UartDeviceImpl_S *impl = UartDeviceImplConvert(object);
|
|
return impl->mUartImpl->UartSend(buff, buffLength);
|
|
}
|
|
static const ssize_t UartRecv(UartDevice *object, void *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));
|
|
} |