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 
25 using namespace std::chrono_literals;
26 namespace Hdc {
HdcHostUART(HdcServer &serverIn, ExternInterface &externInterface)27 HdcHostUART::HdcHostUART(HdcServer &serverIn, ExternInterface &externInterface)
28     : HdcUARTBase(serverIn, externInterface), server(serverIn)
29 {
30     uv_timer_init(&server.loopMain, &devUartWatcher);
31 }
32 
~HdcHostUART()33 HdcHostUART::~HdcHostUART()
34 {
35     Stop();
36 }
37 
Initial()38 int HdcHostUART::Initial()
39 {
40     uartOpened = false; // modRunning
41     return StartupUARTWork();
42 }
43 
NeedStop(const HSession hSession)44 bool HdcHostUART::NeedStop(const HSession hSession)
45 {
46     return (!uartOpened or (hSession->isDead and hSession->ref == 0));
47 }
48 
IsDeviceOpened(const HdcUART &uart)49 bool 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 
UartWriteThread()59 void 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 
UartReadThread(HSession hSession)75 void 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 ?
EnumSerialPort(bool &portChange)115 bool 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
233 std::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
246 int 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 
304 bool 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 
324 int 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 
417 void 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 
452 bool 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 
468 bool 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
483 HSession 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 
508 RetErrCode 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 
525 HSession HdcHostUART::ConnectDaemon(const std::string &connectKey)
526 {
527     WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
528     OpenSerialPort(connectKey);
529     return nullptr;
530 }
531 
532 /*
533 This function does the following:
534 1. Existing serial device, check whether a session is established, if not, go to establish
535 2. The connection is established but the serial device does not exist, delete the session
536 */
537 void 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 
567 bool 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 
614 void 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 
632 HSession HdcHostUART::GetSession(const uint32_t sessionId, bool)
633 {
634     return server.AdminSession(OP_QUERY, sessionId, nullptr);
635 }
636 void 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 
653 void 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 ?
678 void 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 
691 void 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 
723 std::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 
746 bool 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 
770 void 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 
777 void 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