* Copyright (C) 2021 Huawei Device Co., Ltd.
* 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.
*/
#ifdef HDC_SUPPORT_UART
#include "host_uart.h"
#include <mutex>
#include <thread>
#include "server.h"
using namespace std::chrono_literals;
namespace Hdc {
HdcHostUART::HdcHostUART(HdcServer &serverIn, ExternInterface &externInterface)
: HdcUARTBase(serverIn, externInterface), server(serverIn)
{
uv_timer_init(&server.loopMain, &devUartWatcher);
}
HdcHostUART::~HdcHostUART()
{
Stop();
}
int HdcHostUART::Initial()
{
uartOpened = false;
return StartupUARTWork();
}
bool HdcHostUART::NeedStop(const HSession hSession)
{
return (!uartOpened or (hSession->isDead and hSession->ref == 0));
}
bool HdcHostUART::IsDeviceOpened(const HdcUART &uart)
{
#ifdef HOST_MINGW
return uart.devUartHandle != INVALID_HANDLE_VALUE;
#else
return uart.devUartHandle >= 0;
#endif
}
void HdcHostUART::UartWriteThread()
{
while (true) {
WRITE_LOG(LOG_DEBUG, "%s wait sendLock.", __FUNCTION__);
transfer.Wait();
if (stopped) {
break;
}
SendPkgInUARTOutMap();
}
WRITE_LOG(LOG_INFO, "Leave %s", __FUNCTION__);
return;
}
void HdcHostUART::UartReadThread(HSession hSession)
{
HUART hUART = hSession->hUART;
vector<uint8_t> dataReadBuf;
WRITE_LOG(LOG_DEBUG, "%s devUartHandle:%d", __FUNCTION__, hUART->devUartHandle);
size_t expectedSize = 0;
while (dataReadBuf.size() < MAX_READ_BUFFER) {
if (NeedStop(hSession)) {
WRITE_LOG(LOG_FATAL, "%s stop ", __FUNCTION__);
break;
}
ssize_t bytesRead = ReadUartDev(dataReadBuf, expectedSize, *hUART);
if (bytesRead < 0) {
WRITE_LOG(LOG_INFO, "%s read got fail , free the session", __FUNCTION__);
OnTransferError(hSession);
} else if (bytesRead == 0) {
WRITE_LOG(LOG_DEBUG, "%s read %zd, clean the data try read again.", __FUNCTION__,
bytesRead);
expectedSize = 0;
dataReadBuf.clear();
continue;
}
WRITE_LOG(LOG_DEBUG, "%s bytesRead:%d, dataReadBuf.size():%d.", __FUNCTION__, bytesRead,
dataReadBuf.size());
if (dataReadBuf.size() < sizeof(UartHead)) {
continue;
}
WRITE_LOG(LOG_DEBUG, "%s PackageProcess dataReadBuf.size():%d.", __FUNCTION__,
dataReadBuf.size());
expectedSize = PackageProcess(dataReadBuf, hSession);
}
WRITE_LOG(LOG_INFO, "Leave %s", __FUNCTION__);
return;
}
bool HdcHostUART::EnumSerialPort(bool &portChange)
{
std::vector<string> newPortInfo;
serialPortRemoved.clear();
bool bRet = true;
#ifdef HOST_MINGW
constexpr int MAX_KEY_LENGTH = 255;
constexpr int MAX_VALUE_NAME = 16383;
HKEY hKey;
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
TCHAR achClass[MAX_PATH] = _T("");
DWORD cchClassName = MAX_PATH;
DWORD cSubKeys = 0;
DWORD cbMaxSubKey;
DWORD cchMaxClass;
DWORD cKeyNum;
DWORD cchMaxValue;
DWORD cbMaxValueData;
DWORD cbSecurityDescriptor;
FILETIME ftLastWriteTime;
LSTATUS iRet = -1;
std::string port;
TCHAR strDSName[MAX_VALUE_NAME];
if (memset_s(strDSName, sizeof(TCHAR) * MAX_VALUE_NAME, 0, sizeof(TCHAR) * MAX_VALUE_NAME) !=
EOK) {
return false;
}
DWORD nValueType = 0;
DWORD nBuffLen = 10;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0,
KEY_READ, &hKey)) {
iRet = RegQueryInfoKey(hKey, achClass, &cchClassName, NULL, &cSubKeys, &cbMaxSubKey,
&cchMaxClass, &cKeyNum, &cchMaxValue, &cbMaxValueData,
&cbSecurityDescriptor, &ftLastWriteTime);
if (ERROR_SUCCESS == iRet) {
for (DWORD i = 0; i < cKeyNum; i++) {
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
nBuffLen = MAX_KEY_LENGTH;
if (ERROR_SUCCESS == RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL,
(LPBYTE)strDSName, &nBuffLen)) {
#ifdef UNICODE
strPortName = WstringToString(strDSName);
#else
port = std::string(strDSName);
#endif
newPortInfo.push_back(port);
auto it = std::find(serialPortInfo.begin(), serialPortInfo.end(), port);
if (it == serialPortInfo.end()) {
portChange = true;
WRITE_LOG(LOG_DEBUG, "%s:new port %s", __FUNCTION__, port.c_str());
}
} else {
bRet = false;
WRITE_LOG(LOG_DEBUG, "%s RegEnumValue fail. %d", __FUNCTION__, GetLastError());
}
}
} else {
bRet = false;
WRITE_LOG(LOG_DEBUG, "%s RegQueryInfoKey failed %d", __FUNCTION__, GetLastError());
}
} else {
bRet = false;
WRITE_LOG(LOG_DEBUG, "%s RegOpenKeyEx fail %d", __FUNCTION__, GetLastError());
}
RegCloseKey(hKey);
#endif
#if defined(HOST_LINUX)||defined(HOST_MAC)
DIR *dir = opendir("/dev");
dirent *p = NULL;
while (dir != nullptr && ((p = readdir(dir)) != nullptr)) {
#ifdef HOST_LINUX
if (p->d_name[0] != '.' && string(p->d_name).find("tty") != std::string::npos) {
#else
if (p->d_name[0] != '.' && string(p->d_name).find("serial") != std::string::npos) {
#endif
string port = "/dev/" + string(p->d_name);
if (port.find("/dev/ttyUSB") == 0 || port.find("/dev/ttySerial") == 0 || port.find("/dev/cu.") == 0) {
newPortInfo.push_back(port);
auto it = std::find(serialPortInfo.begin(), serialPortInfo.end(), port);
if (it == serialPortInfo.end()) {
portChange = true;
WRITE_LOG(LOG_DEBUG, "new port:%s", port.c_str());
}
}
}
}
if (dir != nullptr) {
closedir(dir);
}
#endif
for (auto &oldPort : serialPortInfo) {
auto it = std::find(newPortInfo.begin(), newPortInfo.end(), oldPort);
if (it == newPortInfo.end()) {
serialPortRemoved.emplace_back(oldPort);
}
}
if (!portChange) {
if (serialPortInfo.size() != newPortInfo.size()) {
portChange = true;
}
}
if (portChange) {
serialPortInfo.swap(newPortInfo);
}
return bRet;
}
#ifdef HOST_MINGW
std::string WstringToString(const std::wstring &wstr)
{
if (wstr.empty()) {
return std::string();
}
int size = WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string ret = std::string(size, 0);
WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), &ret[0], size, NULL,
NULL);
return ret;
}
int HdcHostUART::WinSetSerial(HUART hUART, string serialPort, int byteSize, int eqBaudRate)
{
int winRet = RET_SUCCESS;
COMMTIMEOUTS timeouts;
GetCommTimeouts(hUART->devUartHandle, &timeouts);
int interTimeout = 5;
timeouts.ReadIntervalTimeout = interTimeout;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hUART->devUartHandle, &timeouts);
constexpr int max = DEFAULT_BAUD_RATE_VALUE / 8 * 2;
do {
if (!SetupComm(hUART->devUartHandle, max, max)) {
WRITE_LOG(LOG_WARN, "SetupComm %s fail, err:%d.", serialPort.c_str(), GetLastError());
winRet = ERR_GENERIC;
break;
}
DCB dcb;
if (!GetCommState(hUART->devUartHandle, &dcb)) {
WRITE_LOG(LOG_WARN, "GetCommState %s fail, err:%d.", serialPort.c_str(),
GetLastError());
winRet = ERR_GENERIC;
}
dcb.DCBlength = sizeof(DCB);
dcb.BaudRate = eqBaudRate;
dcb.Parity = 0;
dcb.ByteSize = byteSize;
dcb.StopBits = ONESTOPBIT;
if (!SetCommState(hUART->devUartHandle, &dcb)) {
WRITE_LOG(LOG_WARN, "SetCommState %s fail, err:%d.", serialPort.c_str(),
GetLastError());
winRet = ERR_GENERIC;
break;
}
if (!PurgeComm(hUART->devUartHandle,
PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT)) {
WRITE_LOG(LOG_WARN, "PurgeComm %s fail, err:%d.", serialPort.c_str(), GetLastError());
winRet = ERR_GENERIC;
break;
}
DWORD dwError;
COMSTAT cs;
if (!ClearCommError(hUART->devUartHandle, &dwError, &cs)) {
WRITE_LOG(LOG_WARN, "ClearCommError %s fail, err:%d.", serialPort.c_str(),
GetLastError());
winRet = ERR_GENERIC;
break;
}
} while (false);
if (winRet != RET_SUCCESS) {
CloseSerialPort(hUART);
}
return winRet;
}
#endif
bool HdcHostUART::WaitUartIdle(HdcUART &uart, bool retry)
{
std::vector<uint8_t> readBuf;
WRITE_LOG(LOG_DEBUG, "%s clear read", __FUNCTION__);
ssize_t ret = ReadUartDev(readBuf, 1, uart);
if (ret == 0) {
WRITE_LOG(LOG_DEBUG, "%s port read timeout", __FUNCTION__);
return true;
} else {
WRITE_LOG(LOG_WARN, "%s port read something %zd", __FUNCTION__, ret);
if (retry) {
return WaitUartIdle(uart, false);
} else {
return false;
}
}
return false;
}
int HdcHostUART::OpenSerialPort(const std::string &connectKey)
{
HdcUART uart;
std::string portName;
uint32_t baudRate;
static int ret = 0;
if (memset_s(&uart, sizeof(HdcUART), 0, sizeof(HdcUART)) != EOK) {
return -1;
}
if (!GetPortFromKey(connectKey, portName, baudRate)) {
WRITE_LOG(LOG_ALL, "%s unknown format %s", __FUNCTION__, Hdc::MaskString(connectKey).c_str());
return -1;
}
do {
ret = 0;
WRITE_LOG(LOG_ALL, "%s try to open %s with rate %u", __FUNCTION__, portName.c_str(),
baudRate);
#ifdef HOST_MINGW
constexpr int numTmp = 2;
TCHAR apiBuf[PORT_NAME_LEN * numTmp];
#ifdef UNICODE
int cnt = _stprintf_s(apiBuf, sizeof(apiBuf), _T("\\\\.\\%S"), port.c_str());
#else
int cnt = _stprintf_s(apiBuf, sizeof(apiBuf), _T("\\\\.\\%s"), portName.c_str());
#endif
if (cnt < 0) {
ret = ERR_GENERIC;
break;
}
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
uart.devUartHandle = CreateFile(apiBuf, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, dwFlagsAndAttributes, NULL);
if (uart.devUartHandle == INVALID_HANDLE_VALUE) {
ret = ERR_GENERIC;
WRITE_LOG(LOG_DEBUG, "%s CreateFile %s err:%d.", __FUNCTION__, portName.c_str(),
GetLastError());
break;
} else {
uart.serialPort = portName;
}
ret = WinSetSerial(&uart, uart.serialPort, UART_BIT2, baudRate);
if (ret != RET_SUCCESS) {
WRITE_LOG(LOG_WARN, "%s WinSetSerial:%s fail.", __FUNCTION__, uart.serialPort.c_str());
break;
}
#endif
#if defined(HOST_LINUX)||defined(HOST_MAC)
string uartName = Base::CanonicalizeSpecPath(portName);
uart.devUartHandle = open(uartName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (uart.devUartHandle < 0) {
constexpr int bufSize = 1024;
char buf[bufSize] = { 0 };
strerror_r(errno, buf, bufSize);
WRITE_LOG(LOG_WARN, "Linux open serial port failed, serialPort:%s, Message : %s",
uart.serialPort.c_str(), buf);
ret = ERR_GENERIC;
break;
}
{
uart.serialPort = portName;
}
SetSerial(uart.devUartHandle, baudRate, UART_BIT2, 'N', 1);
#endif
if (!WaitUartIdle(uart)) {
ret = ERR_GENERIC;
WRITE_LOG(LOG_INFO, "This is not a Idle UART port: %s", uart.serialPort.c_str());
break;
}
if (!ConnectMyNeed(&uart, connectKey)) {
WRITE_LOG(LOG_WARN, "ConnectMyNeed failed");
ret = ERR_GENERIC;
break;
} else {
uartOpened = true;
WRITE_LOG(LOG_INFO,
"Serial Open Successfully! uart.serialPort:%s "
"devUartHandle:%d",
uart.serialPort.c_str(), uart.devUartHandle);
}
break;
} while (false);
if (ret != RET_SUCCESS) {
CloseSerialPort(&uart);
}
return ret;
}
void HdcHostUART::UpdateUARTDaemonInfo(const std::string &connectKey, HSession hSession,
ConnStatus connStatus)
{
HdcDaemonInformation diNew;
HDaemonInfo diNewPtr = &diNew;
diNew.connectKey = connectKey;
diNew.connType = CONN_SERIAL;
diNew.connStatus = connStatus;
diNew.hSession = hSession;
WRITE_LOG(LOG_DEBUG, "%s uart connectKey :%s session %s change to %d", __FUNCTION__,
connectKey.c_str(),
hSession == nullptr ? "<null>" : hSession->ToDebugString().c_str(), connStatus);
if (connStatus == STATUS_UNKNOW) {
server.AdminDaemonMap(OP_REMOVE, connectKey, diNewPtr);
if (hSession != nullptr and hSession->hUART != nullptr) {
connectedPorts.erase(hSession->hUART->serialPort);
}
} else {
if (connStatus == STATUS_CONNECTED) {
if (hSession != nullptr and hSession->hUART != nullptr) {
connectedPorts.emplace(hSession->hUART->serialPort);
}
}
HDaemonInfo diOldPtr = nullptr;
server.AdminDaemonMap(OP_QUERY, connectKey, diOldPtr);
if (diOldPtr == nullptr) {
WRITE_LOG(LOG_DEBUG, "%s add new di", __FUNCTION__);
server.AdminDaemonMap(OP_ADD, connectKey, diNewPtr);
} else {
server.AdminDaemonMap(OP_UPDATE, connectKey, diNewPtr);
}
}
}
bool HdcHostUART::StartUartReadThread(HSession hSession)
{
try {
HUART hUART = hSession->hUART;
hUART->readThread = std::thread([this, hSession]() { this->UartReadThread(hSession); });
} catch (...) {
server.FreeSession(hSession->sessionId);
UpdateUARTDaemonInfo(hSession->connectKey, hSession, STATUS_UNKNOW);
WRITE_LOG(LOG_WARN, "%s failed err", __FUNCTION__);
return false;
}
WRITE_LOG(LOG_INFO, "%s success.", __FUNCTION__);
return true;
}
bool HdcHostUART::StartUartSendThread()
{
WRITE_LOG(LOG_DEBUG, "%s.", __FUNCTION__);
try {
sendThread = std::thread([this]() { this->UartWriteThread(); });
} catch (...) {
WRITE_LOG(LOG_WARN, "%s sendThread create failed", __FUNCTION__);
return false;
}
WRITE_LOG(LOG_INFO, "%s success.", __FUNCTION__);
return true;
}
HSession HdcHostUART::ConnectDaemonByUart(const HSession hSession, const HDaemonInfo)
{
if (!uartOpened) {
WRITE_LOG(LOG_DEBUG, "%s non uart opened.", __FUNCTION__);
return nullptr;
}
HUART hUART = hSession->hUART;
UpdateUARTDaemonInfo(hSession->connectKey, hSession, STATUS_READY);
WRITE_LOG(LOG_DEBUG, "%s :%s", __FUNCTION__, hUART->serialPort.c_str());
if (!StartUartReadThread(hSession)) {
WRITE_LOG(LOG_DEBUG, "%s StartUartReadThread fail.", __FUNCTION__);
return nullptr;
}
externInterface.StartWorkThread(&server.loopMain, server.SessionWorkThread,
Base::FinishWorkThread, hSession);
while (hSession->childLoop.active_handles == 0) {
uv_sleep(1);
}
auto ctrl = server.BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
externInterface.SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
return hSession;
}
RetErrCode HdcHostUART::StartupUARTWork()
{
WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
devUartWatcher.data = this;
constexpr int interval = 3000;
constexpr int delay = 1000;
if (externInterface.UvTimerStart(&devUartWatcher, UvWatchUartDevPlugin, delay, interval) != 0) {
WRITE_LOG(LOG_FATAL, "devUartWatcher start fail");
return ERR_GENERIC;
}
if (!StartUartSendThread()) {
WRITE_LOG(LOG_DEBUG, "%s StartUartSendThread fail.", __FUNCTION__);
return ERR_GENERIC;
}
return RET_SUCCESS;
}
HSession HdcHostUART::ConnectDaemon(const std::string &connectKey)
{
WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
OpenSerialPort(connectKey);
return nullptr;
}
This function does the following:
1. Existing serial device, check whether a session is established, if not, go to establish
2. The connection is established but the serial device does not exist, delete the session
*/
void HdcHostUART::WatchUartDevPlugin()
{
std::lock_guard<std::mutex> lock(semUartDevCheck);
bool portChange = false;
if (!EnumSerialPort(portChange)) {
WRITE_LOG(LOG_WARN, "%s enumDetailsSerialPorts fail.", __FUNCTION__);
} else if (portChange) {
for (const auto &port : serialPortInfo) {
WRITE_LOG(LOG_INFO, "%s found uart port :%s", __FUNCTION__, port.c_str());
HDaemonInfo hdi = nullptr;
server.AdminDaemonMap(OP_QUERY, port, hdi);
if (hdi == nullptr and connectedPorts.find(port) == connectedPorts.end()) {
UpdateUARTDaemonInfo(port, nullptr, STATUS_READY);
}
}
for (const auto &port : serialPortRemoved) {
WRITE_LOG(LOG_INFO, "%s remove uart port :%s", __FUNCTION__, port.c_str());
HDaemonInfo hdi = nullptr;
server.AdminDaemonMap(OP_QUERY, port, hdi);
if (hdi != nullptr and hdi->hSession == nullptr) {
UpdateUARTDaemonInfo(port, nullptr, STATUS_UNKNOW);
}
}
}
}
bool HdcHostUART::ConnectMyNeed(HUART hUART, std::string connectKey)
{
if (connectKey.empty()) {
connectKey = hUART->serialPort;
}
if (connectKey != hUART->serialPort) {
UpdateUARTDaemonInfo(hUART->serialPort, nullptr, STATUS_UNKNOW);
}
UpdateUARTDaemonInfo(connectKey, nullptr, STATUS_READY);
HSession hSession = server.MallocSession(true, CONN_SERIAL, this);
if (!hSession) {
WRITE_LOG(LOG_FATAL, "malloc serial session failed for %s", Hdc::MaskString(connectKey).c_str());
return false;
}
hSession->connectKey = connectKey;
#if defined(HOST_LINUX)||defined(HOST_MAC)
hSession->hUART->devUartHandle = hUART->devUartHandle;
#elif defined(HOST_MINGW)
hSession->hUART->devUartHandle = hUART->devUartHandle;
#endif
hSession->isCheck = isCheck;
hSession->hUART->serialPort = hUART->serialPort;
WRITE_LOG(LOG_DEBUG, "%s connectkey:%s,port:%s", __FUNCTION__, Hdc::MaskString(hSession->connectKey).c_str(),
hUART->serialPort.c_str());
uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
if (waitTimeDoCmd == nullptr) {
WRITE_LOG(LOG_FATAL, "ConnectMyNeed new waitTimeDoCmd failed");
server.FreeSession(hSession->sessionId);
return false;
}
uv_timer_init(&server.loopMain, waitTimeDoCmd);
waitTimeDoCmd->data = hSession;
if (externInterface.UvTimerStart(waitTimeDoCmd, server.UartPreConnect, UV_TIMEOUT, UV_REPEAT) !=
RET_SUCCESS) {
WRITE_LOG(LOG_DEBUG, "%s for %s:%s fail.", __FUNCTION__, Hdc::MaskString(hSession->connectKey).c_str(),
hUART->serialPort.c_str());
delete waitTimeDoCmd;
server.FreeSession(hSession->sessionId);
return false;
}
WRITE_LOG(LOG_DEBUG, "%s %s register a session", __FUNCTION__, hUART->serialPort.c_str());
return true;
}
void HdcHostUART::KickoutZombie(HSession hSession)
{
if (hSession == nullptr or hSession->hUART == nullptr or hSession->isDead) {
return;
}
#ifdef _WIN32
if (hSession->hUART->devUartHandle == INVALID_HANDLE_VALUE) {
return;
}
#else
if (hSession->hUART->devUartHandle < 0) {
return;
}
#endif
WRITE_LOG(LOG_DEBUG, "%s FreeSession %s", __FUNCTION__, hSession->ToDebugString().c_str());
server.FreeSession(hSession->sessionId);
}
HSession HdcHostUART::GetSession(const uint32_t sessionId, bool)
{
return server.AdminSession(OP_QUERY, sessionId, nullptr);
}
void HdcHostUART::CloseSerialPort(const HUART hUART)
{
WRITE_LOG(LOG_DEBUG, "%s try to close dev handle %d", __FUNCTION__, hUART->devUartHandle);
#ifdef _WIN32
if (hUART->devUartHandle != INVALID_HANDLE_VALUE) {
CloseHandle(hUART->devUartHandle);
hUART->devUartHandle = INVALID_HANDLE_VALUE;
}
#else
if (hUART->devUartHandle != -1) {
Base::CloseFd(hUART->devUartHandle);
hUART->devUartHandle = -1;
}
#endif
}
void HdcHostUART::OnTransferErrorInner(const HSession session, bool lock)
{
if (session != nullptr) {
WRITE_LOG(LOG_FATAL, "%s:%s", __FUNCTION__, session->ToDebugString().c_str());
if (session->hUART != nullptr) {
if (IsDeviceOpened(*session->hUART)) {
string echoStr = "ERR: uart link layer transmission error.\n";
server.EchoToClientsForSession(session->sessionId, echoStr);
}
CloseSerialPort(session->hUART);
UpdateUARTDaemonInfo(session->connectKey, session, STATUS_OFFLINE);
}
server.FreeSession(session->sessionId);
if (lock) {
ClearUARTOutMap(session->sessionId);
} else {
ClearUARTOutMapRaw(session->sessionId);
}
}
}
void HdcHostUART::OnTransferError(const HSession session)
{
OnTransferErrorInner(session, true);
}
void HdcHostUART::OnTransferErrorRaw(const HSession session)
{
OnTransferErrorInner(session, false);
}
void HdcHostUART::Restartession(const HSession session)
{
HdcUARTBase::Restartession(session);
if (session != nullptr and session->hUART != nullptr) {
WRITE_LOG(LOG_FATAL, "%s reset serialPort:%s", __FUNCTION__,
session->hUART->serialPort.c_str());
CloseSerialPort(session->hUART);
server.EchoToClientsForSession(session->sessionId,
"uart link released by daemon. need connect again.");
}
}
void HdcHostUART::StopSession(HSession hSession)
{
if (hSession == nullptr) {
WRITE_LOG(LOG_FATAL, "%s hSession is null", __FUNCTION__);
return;
}
WRITE_LOG(LOG_DEBUG, "%s hSession %s will be stop and free", __FUNCTION__,
hSession->ToDebugString().c_str());
HUART hUART = hSession->hUART;
if (hUART == nullptr) {
WRITE_LOG(LOG_FATAL, "%s hUART is null", __FUNCTION__);
} else {
#ifdef _WIN32
CancelIoEx(hUART->devUartHandle, NULL);
#endif
hUART->ioCancel = true;
if (hUART->readThread.joinable()) {
WRITE_LOG(LOG_DEBUG, "wait readThread Stop");
hUART->readThread.join();
} else {
WRITE_LOG(LOG_FATAL, "readThread is not joinable");
}
}
HdcUARTBase::StopSession(hSession);
}
std::vector<std::string> HdcHostUART::StringSplit(std::string source, std::string split)
{
std::vector<std::string> result;
if (!split.empty()) {
size_t pos = 0;
while ((pos = source.find(split)) != std::string::npos) {
std::string token = source.substr(0, pos);
if (!token.empty()) {
result.push_back(token);
}
source.erase(0, pos + split.length());
}
}
if (!source.empty()) {
result.push_back(source);
}
return result;
}
bool HdcHostUART::GetPortFromKey(const std::string &connectKey, std::string &portName,
uint32_t &baudRate)
{
constexpr size_t TWO_ARGS = 2;
std::vector<std::string> result = StringSplit(connectKey, ",");
if (result.size() == TWO_ARGS) {
portName = result[0];
char *endptr = nullptr;
const char *str = result[1].c_str();
unsigned long tmp = std::strtoul(str, &endptr, 10);
if (endptr == str || *endptr != '\0' || tmp > std::numeric_limits<uint32_t>::max()) {
WRITE_LOG(LOG_WARN, "Invalid baud rate: %s", result[1].c_str());
return false;
}
baudRate = static_cast<uint32_t>(tmp);
return true;
} else if (result.size() == 1) {
portName = result[0];
baudRate = DEFAULT_BAUD_RATE_VALUE;
return true;
} else {
return false;
}
}
void HdcHostUART::SendUartSoftReset(HSession hSession, uint32_t sessionId)
{
UartHead resetPackage(sessionId, PKG_OPTION_RESET);
resetPackage.dataSize = sizeof(UartHead);
RequestSendPackage(reinterpret_cast<uint8_t *>(&resetPackage), sizeof(UartHead), false);
}
void HdcHostUART::Stop()
{
WRITE_LOG(LOG_DEBUG, "%s Stop!", __FUNCTION__);
if (!stopped) {
externInterface.TryCloseHandle((uv_handle_t *)&devUartWatcher);
uartOpened = false;
stopped = true;
NotifyTransfer();
if (sendThread.joinable()) {
WRITE_LOG(LOG_DEBUG, "%s wait sendThread Stop!", __FUNCTION__);
sendThread.join();
} else {
WRITE_LOG(LOG_FATAL, "%s sendThread is not joinable", __FUNCTION__);
}
}
}
}
#endif