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