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