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