xref: /developtools/hdc/src/host/host_uart.cpp (revision cc290419)
1/*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifdef HDC_SUPPORT_UART
17
18#include "host_uart.h"
19
20#include <mutex>
21#include <thread>
22
23#include "server.h"
24
25using namespace std::chrono_literals;
26namespace Hdc {
27HdcHostUART::HdcHostUART(HdcServer &serverIn, ExternInterface &externInterface)
28    : HdcUARTBase(serverIn, externInterface), server(serverIn)
29{
30    uv_timer_init(&server.loopMain, &devUartWatcher);
31}
32
33HdcHostUART::~HdcHostUART()
34{
35    Stop();
36}
37
38int HdcHostUART::Initial()
39{
40    uartOpened = false; // modRunning
41    return StartupUARTWork();
42}
43
44bool HdcHostUART::NeedStop(const HSession hSession)
45{
46    return (!uartOpened or (hSession->isDead and hSession->ref == 0));
47}
48
49bool HdcHostUART::IsDeviceOpened(const HdcUART &uart)
50{
51    // review why not use uartOpened?
52#ifdef HOST_MINGW
53    return uart.devUartHandle != INVALID_HANDLE_VALUE;
54#else
55    return uart.devUartHandle >= 0;
56#endif
57}
58
59void HdcHostUART::UartWriteThread()
60{
61    // this thread don't care session.
62    while (true) {
63        WRITE_LOG(LOG_DEBUG, "%s wait sendLock.", __FUNCTION__);
64        transfer.Wait();
65        // it almost in wait , so we check stop after wait.
66        if (stopped) {
67            break;
68        }
69        SendPkgInUARTOutMap();
70    }
71    WRITE_LOG(LOG_INFO, "Leave %s", __FUNCTION__);
72    return;
73}
74
75void HdcHostUART::UartReadThread(HSession hSession)
76{
77    HUART hUART = hSession->hUART;
78    vector<uint8_t> dataReadBuf; // each thread/session have it own data buff
79    // If something unexpected happens , max buffer size we allow
80    WRITE_LOG(LOG_DEBUG, "%s devUartHandle:%d", __FUNCTION__, hUART->devUartHandle);
81    size_t expectedSize = 0;
82    while (dataReadBuf.size() < MAX_READ_BUFFER) {
83        if (NeedStop(hSession)) {
84            WRITE_LOG(LOG_FATAL, "%s stop ", __FUNCTION__);
85            break;
86        }
87        ssize_t bytesRead = ReadUartDev(dataReadBuf, expectedSize, *hUART);
88        if (bytesRead < 0) {
89            WRITE_LOG(LOG_INFO, "%s read got fail , free the session", __FUNCTION__);
90            OnTransferError(hSession);
91        } else if (bytesRead == 0) {
92            WRITE_LOG(LOG_DEBUG, "%s read %zd, clean the data try read again.", __FUNCTION__,
93                      bytesRead);
94            // drop current cache
95            expectedSize = 0;
96            dataReadBuf.clear();
97            continue;
98        }
99
100        WRITE_LOG(LOG_DEBUG, "%s bytesRead:%d, dataReadBuf.size():%d.", __FUNCTION__, bytesRead,
101                  dataReadBuf.size());
102
103        if (dataReadBuf.size() < sizeof(UartHead)) {
104            continue; // no enough ,read again
105        }
106        WRITE_LOG(LOG_DEBUG, "%s PackageProcess dataReadBuf.size():%d.", __FUNCTION__,
107                  dataReadBuf.size());
108        expectedSize = PackageProcess(dataReadBuf, hSession);
109    }
110    WRITE_LOG(LOG_INFO, "Leave %s", __FUNCTION__);
111    return;
112}
113
114// review why not use QueryDosDevice ?
115bool HdcHostUART::EnumSerialPort(bool &portChange)
116{
117    std::vector<string> newPortInfo;
118    serialPortRemoved.clear();
119    bool bRet = true;
120
121#ifdef HOST_MINGW
122    constexpr int MAX_KEY_LENGTH = 255;
123    constexpr int MAX_VALUE_NAME = 16383;
124    HKEY hKey;
125    TCHAR achValue[MAX_VALUE_NAME];    // buffer for subkey name
126    DWORD cchValue = MAX_VALUE_NAME;   // size of name string
127    TCHAR achClass[MAX_PATH] = _T(""); // buffer for class name
128    DWORD cchClassName = MAX_PATH;     // size of class string
129    DWORD cSubKeys = 0;                // number of subkeys
130    DWORD cbMaxSubKey;                 // longest subkey size
131    DWORD cchMaxClass;                 // longest class string
132    DWORD cKeyNum;                     // number of values for key
133    DWORD cchMaxValue;                 // longest value name
134    DWORD cbMaxValueData;              // longest value data
135    DWORD cbSecurityDescriptor;        // size of security descriptor
136    FILETIME ftLastWriteTime;          // last write time
137    LSTATUS iRet = -1;
138    std::string port;
139    TCHAR strDSName[MAX_VALUE_NAME];
140    if (memset_s(strDSName, sizeof(TCHAR) * MAX_VALUE_NAME, 0, sizeof(TCHAR) * MAX_VALUE_NAME) !=
141        EOK) {
142        return false;
143    }
144    DWORD nValueType = 0;
145    DWORD nBuffLen = 10;
146    if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0,
147                                      KEY_READ, &hKey)) {
148        // Get the class name and the value count.
149        iRet = RegQueryInfoKey(hKey, achClass, &cchClassName, NULL, &cSubKeys, &cbMaxSubKey,
150                               &cchMaxClass, &cKeyNum, &cchMaxValue, &cbMaxValueData,
151                               &cbSecurityDescriptor, &ftLastWriteTime);
152        // Enumerate the key values.
153        if (ERROR_SUCCESS == iRet) {
154            for (DWORD i = 0; i < cKeyNum; i++) {
155                cchValue = MAX_VALUE_NAME;
156                achValue[0] = '\0';
157                nBuffLen = MAX_KEY_LENGTH;
158                if (ERROR_SUCCESS == RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL,
159                                                  (LPBYTE)strDSName, &nBuffLen)) {
160#ifdef UNICODE
161                    strPortName = WstringToString(strDSName);
162#else
163                    port = std::string(strDSName);
164#endif
165                    newPortInfo.push_back(port);
166                    auto it = std::find(serialPortInfo.begin(), serialPortInfo.end(), port);
167                    if (it == serialPortInfo.end()) {
168                        portChange = true;
169                        WRITE_LOG(LOG_DEBUG, "%s:new port %s", __FUNCTION__, port.c_str());
170                    }
171                } else {
172                    bRet = false;
173                    WRITE_LOG(LOG_DEBUG, "%s RegEnumValue fail. %d", __FUNCTION__, GetLastError());
174                }
175            }
176        } else {
177            bRet = false;
178            WRITE_LOG(LOG_DEBUG, "%s RegQueryInfoKey failed %d", __FUNCTION__, GetLastError());
179        }
180    } else {
181        bRet = false;
182        WRITE_LOG(LOG_DEBUG, "%s RegOpenKeyEx fail %d", __FUNCTION__, GetLastError());
183    }
184    RegCloseKey(hKey);
185#endif
186#if defined(HOST_LINUX)||defined(HOST_MAC)
187    DIR *dir = opendir("/dev");
188    dirent *p = NULL;
189
190    while (dir != nullptr && ((p = readdir(dir)) != nullptr)) {
191#ifdef HOST_LINUX
192        if (p->d_name[0] != '.' && string(p->d_name).find("tty") != std::string::npos) {
193#else
194        if (p->d_name[0] != '.' && string(p->d_name).find("serial") != std::string::npos) {
195#endif
196            string port = "/dev/" + string(p->d_name);
197            if (port.find("/dev/ttyUSB") == 0 || port.find("/dev/ttySerial") == 0 || port.find("/dev/cu.") == 0) {
198                newPortInfo.push_back(port);
199                auto it = std::find(serialPortInfo.begin(), serialPortInfo.end(), port);
200                if (it == serialPortInfo.end()) {
201                    portChange = true;
202                    WRITE_LOG(LOG_DEBUG, "new port:%s", port.c_str());
203                }
204            }
205        }
206    }
207    if (dir != nullptr) {
208        closedir(dir);
209    }
210#endif
211    for (auto &oldPort : serialPortInfo) {
212        auto it = std::find(newPortInfo.begin(), newPortInfo.end(), oldPort);
213        if (it == newPortInfo.end()) {
214            // not found in new port list
215            // we need remove the connect info
216            serialPortRemoved.emplace_back(oldPort);
217        }
218    }
219
220    if (!portChange) {
221        // new scan empty , same as port changed
222        if (serialPortInfo.size() != newPortInfo.size()) {
223            portChange = true;
224        }
225    }
226    if (portChange) {
227        serialPortInfo.swap(newPortInfo);
228    }
229    return bRet;
230}
231
232#ifdef HOST_MINGW
233std::string WstringToString(const std::wstring &wstr)
234{
235    if (wstr.empty()) {
236        return std::string();
237    }
238    int size = WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
239    std::string ret = std::string(size, 0);
240    WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), &ret[0], size, NULL,
241                        NULL); // CP_UTF8
242    return ret;
243}
244
245// review rename for same func from linux
246int HdcHostUART::WinSetSerial(HUART hUART, string serialPort, int byteSize, int eqBaudRate)
247{
248    int winRet = RET_SUCCESS;
249    COMMTIMEOUTS timeouts;
250    GetCommTimeouts(hUART->devUartHandle, &timeouts);
251    int interTimeout = 5;
252    timeouts.ReadIntervalTimeout = interTimeout;
253    timeouts.ReadTotalTimeoutMultiplier = 0;
254    timeouts.ReadTotalTimeoutConstant = 0;
255    timeouts.WriteTotalTimeoutMultiplier = 0;
256    timeouts.WriteTotalTimeoutConstant = 0;
257    SetCommTimeouts(hUART->devUartHandle, &timeouts);
258    constexpr int max = DEFAULT_BAUD_RATE_VALUE / 8 * 2; // 2 second buffer size
259    do {
260        if (!SetupComm(hUART->devUartHandle, max, max)) {
261            WRITE_LOG(LOG_WARN, "SetupComm %s fail, err:%d.", serialPort.c_str(), GetLastError());
262            winRet = ERR_GENERIC;
263            break;
264        }
265        DCB dcb;
266        if (!GetCommState(hUART->devUartHandle, &dcb)) {
267            WRITE_LOG(LOG_WARN, "GetCommState %s fail, err:%d.", serialPort.c_str(),
268                      GetLastError());
269            winRet = ERR_GENERIC;
270        }
271        dcb.DCBlength = sizeof(DCB);
272        dcb.BaudRate = eqBaudRate;
273        dcb.Parity = 0;
274        dcb.ByteSize = byteSize;
275        dcb.StopBits = ONESTOPBIT;
276        if (!SetCommState(hUART->devUartHandle, &dcb)) {
277            WRITE_LOG(LOG_WARN, "SetCommState %s fail, err:%d.", serialPort.c_str(),
278                      GetLastError());
279            winRet = ERR_GENERIC;
280            break;
281        }
282        if (!PurgeComm(hUART->devUartHandle,
283                       PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT)) {
284            WRITE_LOG(LOG_WARN, "PurgeComm  %s fail, err:%d.", serialPort.c_str(), GetLastError());
285            winRet = ERR_GENERIC;
286            break;
287        }
288        DWORD dwError;
289        COMSTAT cs;
290        if (!ClearCommError(hUART->devUartHandle, &dwError, &cs)) {
291            WRITE_LOG(LOG_WARN, "ClearCommError %s fail, err:%d.", serialPort.c_str(),
292                      GetLastError());
293            winRet = ERR_GENERIC;
294            break;
295        }
296    } while (false);
297    if (winRet != RET_SUCCESS) {
298        CloseSerialPort(hUART);
299    }
300    return winRet;
301}
302#endif // HOST_MINGW
303
304bool HdcHostUART::WaitUartIdle(HdcUART &uart, bool retry)
305{
306    std::vector<uint8_t> readBuf;
307    WRITE_LOG(LOG_DEBUG, "%s clear read", __FUNCTION__);
308    ssize_t ret = ReadUartDev(readBuf, 1, uart);
309    if (ret == 0) {
310        WRITE_LOG(LOG_DEBUG, "%s port read timeout", __FUNCTION__);
311        return true;
312    } else {
313        WRITE_LOG(LOG_WARN, "%s port read something %zd", __FUNCTION__, ret);
314        if (retry) {
315            // we will read again , but only retry one time
316            return WaitUartIdle(uart, false);
317        } else {
318            return false;
319        }
320    }
321    return false;
322}
323
324int HdcHostUART::OpenSerialPort(const std::string &connectKey)
325{
326    HdcUART uart;
327    std::string portName;
328    uint32_t baudRate;
329    static int ret = 0;
330
331    if (memset_s(&uart, sizeof(HdcUART), 0, sizeof(HdcUART)) != EOK) {
332        return -1;
333    }
334
335    if (!GetPortFromKey(connectKey, portName, baudRate)) {
336        WRITE_LOG(LOG_ALL, "%s unknown format %s", __FUNCTION__, Hdc::MaskString(connectKey).c_str());
337        return -1;
338    }
339    do {
340        ret = 0;
341        WRITE_LOG(LOG_ALL, "%s try to open %s with rate %u", __FUNCTION__, portName.c_str(),
342                  baudRate);
343
344#ifdef HOST_MINGW
345        constexpr int numTmp = 2;
346        // review change to wstring ?
347        TCHAR apiBuf[PORT_NAME_LEN * numTmp];
348#ifdef UNICODE
349        int cnt = _stprintf_s(apiBuf, sizeof(apiBuf), _T("\\\\.\\%S"), port.c_str());
350#else
351        int cnt = _stprintf_s(apiBuf, sizeof(apiBuf), _T("\\\\.\\%s"), portName.c_str());
352#endif
353        if (cnt < 0) {
354            ret = ERR_GENERIC;
355            break;
356        }
357        DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
358        uart.devUartHandle = CreateFile(apiBuf, GENERIC_READ | GENERIC_WRITE, 0, NULL,
359                                        OPEN_EXISTING, dwFlagsAndAttributes, NULL);
360        if (uart.devUartHandle == INVALID_HANDLE_VALUE) {
361            ret = ERR_GENERIC;
362            WRITE_LOG(LOG_DEBUG, "%s CreateFile %s err:%d.", __FUNCTION__, portName.c_str(),
363                      GetLastError());
364            break; // review for onethan one uart , here we need change to continue?
365        } else {
366            uart.serialPort = portName;
367        }
368        ret = WinSetSerial(&uart, uart.serialPort, UART_BIT2, baudRate);
369        if (ret != RET_SUCCESS) {
370            WRITE_LOG(LOG_WARN, "%s WinSetSerial:%s fail.", __FUNCTION__, uart.serialPort.c_str());
371            break;
372        }
373#endif
374
375#if defined(HOST_LINUX)||defined(HOST_MAC)
376        string uartName = Base::CanonicalizeSpecPath(portName);
377        uart.devUartHandle = open(uartName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
378        if (uart.devUartHandle < 0) {
379            constexpr int bufSize = 1024;
380            char buf[bufSize] = { 0 };
381            strerror_r(errno, buf, bufSize);
382            WRITE_LOG(LOG_WARN, "Linux open serial port failed, serialPort:%s, Message : %s",
383                      uart.serialPort.c_str(), buf);
384            ret = ERR_GENERIC;
385            break;
386        }
387        {
388            uart.serialPort = portName;
389        }
390        SetSerial(uart.devUartHandle, baudRate, UART_BIT2, 'N', 1);
391#endif
392        // if the dev is idle
393        if (!WaitUartIdle(uart)) {
394            ret = ERR_GENERIC;
395            WRITE_LOG(LOG_INFO, "This is not a Idle UART port: %s", uart.serialPort.c_str());
396            break;
397        }
398        if (!ConnectMyNeed(&uart, connectKey)) {
399            WRITE_LOG(LOG_WARN, "ConnectMyNeed failed");
400            ret = ERR_GENERIC;
401            break;
402        } else {
403            uartOpened = true;
404            WRITE_LOG(LOG_INFO,
405                      "Serial Open Successfully! uart.serialPort:%s "
406                      "devUartHandle:%d",
407                      uart.serialPort.c_str(), uart.devUartHandle);
408        }
409        break;
410    } while (false);
411    if (ret != RET_SUCCESS) {
412        CloseSerialPort(&uart);
413    }
414    return ret;
415}
416
417void HdcHostUART::UpdateUARTDaemonInfo(const std::string &connectKey, HSession hSession,
418                                       ConnStatus connStatus)
419{
420    // add to list
421    HdcDaemonInformation diNew;
422    HDaemonInfo diNewPtr = &diNew;
423    diNew.connectKey = connectKey;
424    diNew.connType = CONN_SERIAL;
425    diNew.connStatus = connStatus;
426    diNew.hSession = hSession;
427    WRITE_LOG(LOG_DEBUG, "%s uart connectKey :%s session %s change to %d", __FUNCTION__,
428              connectKey.c_str(),
429              hSession == nullptr ? "<null>" : hSession->ToDebugString().c_str(), connStatus);
430    if (connStatus == STATUS_UNKNOW) {
431        server.AdminDaemonMap(OP_REMOVE, connectKey, diNewPtr);
432        if (hSession != nullptr and hSession->hUART != nullptr) {
433            connectedPorts.erase(hSession->hUART->serialPort);
434        }
435    } else {
436        if (connStatus == STATUS_CONNECTED) {
437            if (hSession != nullptr and hSession->hUART != nullptr) {
438                connectedPorts.emplace(hSession->hUART->serialPort);
439            }
440        }
441        HDaemonInfo diOldPtr = nullptr;
442        server.AdminDaemonMap(OP_QUERY, connectKey, diOldPtr);
443        if (diOldPtr == nullptr) {
444            WRITE_LOG(LOG_DEBUG, "%s add new di", __FUNCTION__);
445            server.AdminDaemonMap(OP_ADD, connectKey, diNewPtr);
446        } else {
447            server.AdminDaemonMap(OP_UPDATE, connectKey, diNewPtr);
448        }
449    }
450}
451
452bool HdcHostUART::StartUartReadThread(HSession hSession)
453{
454    try {
455        HUART hUART = hSession->hUART;
456        hUART->readThread = std::thread([this, hSession]() { this->UartReadThread(hSession); });
457    } catch (...) {
458        server.FreeSession(hSession->sessionId);
459        UpdateUARTDaemonInfo(hSession->connectKey, hSession, STATUS_UNKNOW);
460        WRITE_LOG(LOG_WARN, "%s failed err", __FUNCTION__);
461        return false;
462    }
463
464    WRITE_LOG(LOG_INFO, "%s success.", __FUNCTION__);
465    return true;
466}
467
468bool HdcHostUART::StartUartSendThread()
469{
470    WRITE_LOG(LOG_DEBUG, "%s.", __FUNCTION__);
471    try {
472        sendThread = std::thread([this]() { this->UartWriteThread(); });
473    } catch (...) {
474        WRITE_LOG(LOG_WARN, "%s sendThread create failed", __FUNCTION__);
475        return false;
476    }
477
478    WRITE_LOG(LOG_INFO, "%s success.", __FUNCTION__);
479    return true;
480}
481
482// Determines that daemonInfo must have the device
483HSession HdcHostUART::ConnectDaemonByUart(const HSession hSession, const HDaemonInfo)
484{
485    if (!uartOpened) {
486        WRITE_LOG(LOG_DEBUG, "%s non uart opened.", __FUNCTION__);
487        return nullptr;
488    }
489    HUART hUART = hSession->hUART;
490    UpdateUARTDaemonInfo(hSession->connectKey, hSession, STATUS_READY);
491    WRITE_LOG(LOG_DEBUG, "%s :%s", __FUNCTION__, hUART->serialPort.c_str());
492    if (!StartUartReadThread(hSession)) {
493        WRITE_LOG(LOG_DEBUG, "%s StartUartReadThread fail.", __FUNCTION__);
494        return nullptr;
495    }
496
497    externInterface.StartWorkThread(&server.loopMain, server.SessionWorkThread,
498                                    Base::FinishWorkThread, hSession);
499    // wait for thread up
500    while (hSession->childLoop.active_handles == 0) {
501        uv_sleep(1);
502    }
503    auto ctrl = server.BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
504    externInterface.SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
505    return hSession;
506}
507
508RetErrCode HdcHostUART::StartupUARTWork()
509{
510    WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
511    devUartWatcher.data = this;
512    constexpr int interval = 3000;
513    constexpr int delay = 1000;
514    if (externInterface.UvTimerStart(&devUartWatcher, UvWatchUartDevPlugin, delay, interval) != 0) {
515        WRITE_LOG(LOG_FATAL, "devUartWatcher start fail");
516        return ERR_GENERIC;
517    }
518    if (!StartUartSendThread()) {
519        WRITE_LOG(LOG_DEBUG, "%s StartUartSendThread fail.", __FUNCTION__);
520        return ERR_GENERIC;
521    }
522    return RET_SUCCESS;
523}
524
525HSession HdcHostUART::ConnectDaemon(const std::string &connectKey)
526{
527    WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
528    OpenSerialPort(connectKey);
529    return nullptr;
530}
531
532/*
533This function does the following:
5341. Existing serial device, check whether a session is established, if not, go to establish
5352. The connection is established but the serial device does not exist, delete the session
536*/
537void HdcHostUART::WatchUartDevPlugin()
538{
539    std::lock_guard<std::mutex> lock(semUartDevCheck);
540    bool portChange = false;
541
542    if (!EnumSerialPort(portChange)) {
543        WRITE_LOG(LOG_WARN, "%s enumDetailsSerialPorts fail.", __FUNCTION__);
544    } else if (portChange) {
545        for (const auto &port : serialPortInfo) {
546            WRITE_LOG(LOG_INFO, "%s found uart port :%s", __FUNCTION__, port.c_str());
547            // check port have session
548            HDaemonInfo hdi = nullptr;
549            server.AdminDaemonMap(OP_QUERY, port, hdi);
550            if (hdi == nullptr and connectedPorts.find(port) == connectedPorts.end()) {
551                UpdateUARTDaemonInfo(port, nullptr, STATUS_READY);
552            }
553        }
554        for (const auto &port : serialPortRemoved) {
555            WRITE_LOG(LOG_INFO, "%s remove uart port :%s", __FUNCTION__, port.c_str());
556            // check port have session
557            HDaemonInfo hdi = nullptr;
558            server.AdminDaemonMap(OP_QUERY, port, hdi);
559            if (hdi != nullptr and hdi->hSession == nullptr) {
560                // we only remove the empty port
561                UpdateUARTDaemonInfo(port, nullptr, STATUS_UNKNOW);
562            }
563        }
564    }
565}
566
567bool HdcHostUART::ConnectMyNeed(HUART hUART, std::string connectKey)
568{
569    // we never use port to connect, we use connect key
570    if (connectKey.empty()) {
571        connectKey = hUART->serialPort;
572    }
573    if (connectKey != hUART->serialPort) {
574        UpdateUARTDaemonInfo(hUART->serialPort, nullptr, STATUS_UNKNOW);
575    }
576    UpdateUARTDaemonInfo(connectKey, nullptr, STATUS_READY);
577
578    HSession hSession = server.MallocSession(true, CONN_SERIAL, this);
579    if (!hSession) {
580        WRITE_LOG(LOG_FATAL, "malloc serial session failed for %s", Hdc::MaskString(connectKey).c_str());
581        return false;
582    }
583    hSession->connectKey = connectKey;
584#if defined(HOST_LINUX)||defined(HOST_MAC)
585    hSession->hUART->devUartHandle = hUART->devUartHandle;
586#elif defined(HOST_MINGW)
587    hSession->hUART->devUartHandle = hUART->devUartHandle;
588#endif
589
590    hSession->isCheck = isCheck;
591    hSession->hUART->serialPort = hUART->serialPort;
592    WRITE_LOG(LOG_DEBUG, "%s connectkey:%s,port:%s", __FUNCTION__, Hdc::MaskString(hSession->connectKey).c_str(),
593              hUART->serialPort.c_str());
594    uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
595    if (waitTimeDoCmd == nullptr) {
596        WRITE_LOG(LOG_FATAL, "ConnectMyNeed new waitTimeDoCmd failed");
597        server.FreeSession(hSession->sessionId);
598        return false;
599    }
600    uv_timer_init(&server.loopMain, waitTimeDoCmd);
601    waitTimeDoCmd->data = hSession;
602    if (externInterface.UvTimerStart(waitTimeDoCmd, server.UartPreConnect, UV_TIMEOUT, UV_REPEAT) !=
603        RET_SUCCESS) {
604        WRITE_LOG(LOG_DEBUG, "%s for %s:%s fail.", __FUNCTION__, Hdc::MaskString(hSession->connectKey).c_str(),
605                  hUART->serialPort.c_str());
606        server.FreeSession(hSession->sessionId);
607        return false;
608    }
609    WRITE_LOG(LOG_DEBUG, "%s %s register a session", __FUNCTION__, hUART->serialPort.c_str());
610
611    return true;
612}
613
614void HdcHostUART::KickoutZombie(HSession hSession)
615{
616    if (hSession == nullptr or hSession->hUART == nullptr or hSession->isDead) {
617        return;
618    }
619#ifdef _WIN32
620    if (hSession->hUART->devUartHandle == INVALID_HANDLE_VALUE) {
621        return;
622    }
623#else
624    if (hSession->hUART->devUartHandle < 0) {
625        return;
626    }
627#endif
628    WRITE_LOG(LOG_DEBUG, "%s FreeSession %s", __FUNCTION__, hSession->ToDebugString().c_str());
629    server.FreeSession(hSession->sessionId);
630}
631
632HSession HdcHostUART::GetSession(const uint32_t sessionId, bool)
633{
634    return server.AdminSession(OP_QUERY, sessionId, nullptr);
635}
636void HdcHostUART::CloseSerialPort(const HUART hUART)
637{
638    WRITE_LOG(LOG_DEBUG, "%s try to close dev handle %d", __FUNCTION__, hUART->devUartHandle);
639
640#ifdef _WIN32
641    if (hUART->devUartHandle != INVALID_HANDLE_VALUE) {
642        CloseHandle(hUART->devUartHandle);
643        hUART->devUartHandle = INVALID_HANDLE_VALUE;
644    }
645#else
646    if (hUART->devUartHandle != -1) {
647        Base::CloseFd(hUART->devUartHandle);
648        hUART->devUartHandle = -1;
649    }
650#endif
651}
652
653void HdcHostUART::OnTransferError(const HSession session)
654{
655    if (session != nullptr) {
656        WRITE_LOG(LOG_FATAL, "%s:%s", __FUNCTION__, session->ToDebugString().c_str());
657        if (session->hUART != nullptr) {
658            if (IsDeviceOpened(*session->hUART)) {
659                // same device dont echo twice to client
660                string echoStr = "ERR: uart link layer transmission error.\n";
661                server.EchoToClientsForSession(session->sessionId, echoStr);
662            }
663            // 1. dev opened by other application
664            // 2. dev is plug out
665            // 3. dev line is broken ?
666            // we set the status to empty
667            // watcher will reopen it if it can find this again
668            CloseSerialPort(session->hUART);
669            UpdateUARTDaemonInfo(session->connectKey, session, STATUS_OFFLINE);
670        }
671
672        server.FreeSession(session->sessionId);
673        ClearUARTOutMap(session->sessionId);
674    }
675}
676
677// review what about merge Restartession with OnTransferError ?
678void HdcHostUART::Restartession(const HSession session)
679{
680    HdcUARTBase::Restartession(session);
681    // allow timer watcher make a new session.
682    if (session != nullptr and session->hUART != nullptr) {
683        WRITE_LOG(LOG_FATAL, "%s reset serialPort:%s", __FUNCTION__,
684                  session->hUART->serialPort.c_str());
685        CloseSerialPort(session->hUART); // huart will free , so we must clost it here
686        server.EchoToClientsForSession(session->sessionId,
687                                       "uart link released by daemon. need connect again.");
688    }
689}
690
691void HdcHostUART::StopSession(HSession hSession)
692{
693    if (hSession == nullptr) {
694        WRITE_LOG(LOG_FATAL, "%s hSession is null", __FUNCTION__);
695        return;
696    }
697    WRITE_LOG(LOG_DEBUG, "%s hSession %s will be stop and free", __FUNCTION__,
698              hSession->ToDebugString().c_str());
699    HUART hUART = hSession->hUART;
700    if (hUART == nullptr) {
701        WRITE_LOG(LOG_FATAL, "%s hUART is null", __FUNCTION__);
702    } else {
703#ifdef _WIN32
704        CancelIoEx(hUART->devUartHandle, NULL);
705#endif
706        // we make select always have a timeout in linux
707        // also we make a mark here
708        // ReadUartDev will return for this flag
709        hUART->ioCancel = true;
710
711        if (hUART->readThread.joinable()) {
712            WRITE_LOG(LOG_DEBUG, "wait readThread Stop");
713            hUART->readThread.join();
714        } else {
715            WRITE_LOG(LOG_FATAL, "readThread is not joinable");
716        }
717    }
718
719    // call the base side
720    HdcUARTBase::StopSession(hSession);
721}
722
723std::vector<std::string> HdcHostUART::StringSplit(std::string source, std::string split)
724{
725    std::vector<std::string> result;
726
727    // find
728    if (!split.empty()) {
729        size_t pos = 0;
730        while ((pos = source.find(split)) != std::string::npos) {
731            // split
732            std::string token = source.substr(0, pos);
733            if (!token.empty()) {
734                result.push_back(token);
735            }
736            source.erase(0, pos + split.length());
737        }
738    }
739    // add last token
740    if (!source.empty()) {
741        result.push_back(source);
742    }
743    return result;
744}
745
746bool HdcHostUART::GetPortFromKey(const std::string &connectKey, std::string &portName,
747                                 uint32_t &baudRate)
748{
749    // we support UART_NAME:UART_RATE format
750    // like COM5:115200
751    constexpr size_t TWO_ARGS = 2;
752    std::vector<std::string> result = StringSplit(connectKey, ",");
753    if (result.size() == TWO_ARGS) {
754        portName = result[0];
755        try {
756            baudRate = static_cast<uint32_t>(std::stoul(result[1]));
757        } catch (...) {
758            return false;
759        }
760        return true;
761    } else if (result.size() == 1) {
762        portName = result[0];
763        baudRate = DEFAULT_BAUD_RATE_VALUE;
764        return true;
765    } else {
766        return false;
767    }
768}
769
770void HdcHostUART::SendUartSoftReset(HSession hSession, uint32_t sessionId)
771{
772    UartHead resetPackage(sessionId, PKG_OPTION_RESET);
773    resetPackage.dataSize = sizeof(UartHead);
774    RequestSendPackage(reinterpret_cast<uint8_t *>(&resetPackage), sizeof(UartHead), false);
775}
776
777void HdcHostUART::Stop()
778{
779    WRITE_LOG(LOG_DEBUG, "%s Stop!", __FUNCTION__);
780    if (!stopped) {
781        externInterface.TryCloseHandle((uv_handle_t *)&devUartWatcher);
782        uartOpened = false;
783        stopped = true;
784        // just click it for exit
785        NotifyTransfer();
786        if (sendThread.joinable()) {
787            WRITE_LOG(LOG_DEBUG, "%s wait sendThread Stop!", __FUNCTION__);
788            sendThread.join();
789        } else {
790            WRITE_LOG(LOG_FATAL, "%s sendThread is not joinable", __FUNCTION__);
791        }
792    }
793}
794} // namespace Hdc
795#endif // HDC_SUPPORT_UART
796