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