/* * 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 #include #include #include #include #include #include #include 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(uartInfo); return (UartDevice *)(((char *)impl) + sizeof(UartDeviceHeader)); }