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 "securec.h" 16#include "uart.h" 17#include "fcntl.h" 18#include <dirent.h> 19#include <cstring> 20#include "log.h" 21 22using namespace std; 23using namespace Hdc; 24 25bool g_ioCancel = false; 26 27// review why not use QueryDosDevice ? 28bool EnumSerialPort(bool &portChange) 29{ 30 std::vector<string> newPortInfo; 31 std::vector<string> serialPortInfo; 32 std::vector<string> serialPortRemoved; 33 serialPortRemoved.clear(); 34 bool bRet = true; 35 36#ifdef HOST_MINGW 37 constexpr int MAX_KEY_LENGTH = 255; 38 constexpr int MAX_VALUE_NAME = 16383; 39 HKEY hKey; 40 TCHAR achValue[MAX_VALUE_NAME]; // buffer for subkey name 41 DWORD cchValue = MAX_VALUE_NAME; // size of name string 42 TCHAR achClass[MAX_PATH] = _T(""); // buffer for class name 43 DWORD cchClassName = MAX_PATH; // size of class string 44 DWORD cSubKeys = 0; // number of subkeys 45 DWORD cbMaxSubKey; // longest subkey size 46 DWORD cchMaxClass; // longest class string 47 DWORD cKeyNum; // number of values for key 48 DWORD cchMaxValue; // longest value name 49 DWORD cbMaxValueData; // longest value data 50 DWORD cbSecurityDescriptor; // size of security descriptor 51 FILETIME ftLastWriteTime; // last write time 52 LSTATUS iRet = -1; 53 std::string port; 54 TCHAR strDSName[MAX_VALUE_NAME]; 55 errno_t nRet = 0; 56 nRet = memset_s(strDSName, sizeof(TCHAR) * MAX_VALUE_NAME, 0, sizeof(TCHAR) * MAX_VALUE_NAME); 57 if (nRet != EOK) { 58 return false; 59 } 60 DWORD nBuffLen = 10; 61 if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, 62 KEY_READ, &hKey)) { 63 // Get the class name and the value count. 64 iRet = RegQueryInfoKey(hKey, achClass, &cchClassName, NULL, &cSubKeys, &cbMaxSubKey, 65 &cchMaxClass, &cKeyNum, &cchMaxValue, &cbMaxValueData, 66 &cbSecurityDescriptor, &ftLastWriteTime); 67 // Enumerate the key values. 68 if (ERROR_SUCCESS == iRet) { 69 for (DWORD i = 0; i < cKeyNum; i++) { 70 cchValue = MAX_VALUE_NAME; 71 achValue[0] = '\0'; 72 nBuffLen = MAX_KEY_LENGTH; 73 if (ERROR_SUCCESS == RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, 74 (LPBYTE)strDSName, &nBuffLen)) { 75#ifdef UNICODE 76 strPortName = WstringToString(strDSName); 77#else 78 port = std::string(strDSName); 79#endif 80 newPortInfo.push_back(port); 81 auto it = std::find(serialPortInfo.begin(), serialPortInfo.end(), port); 82 if (it == serialPortInfo.end()) { 83 portChange = true; 84 } 85 } else { 86 bRet = false; 87 } 88 } 89 } else { 90 bRet = false; 91 } 92 } else { 93 bRet = false; 94 } 95 RegCloseKey(hKey); 96#else 97 DIR *dir = opendir("/dev"); 98 dirent *p = nullptr; 99 if (dir != nullptr) { 100 while ((p = readdir(dir)) != nullptr) { 101#ifdef HOST_LINUX 102 if (p->d_name[0] != '.' && string(p->d_name).find("tty") != std::string::npos) { 103#else 104 if (p->d_name[0] != '.' && string(p->d_name).find("serial") != std::string::npos) { 105#endif 106 string port = "/dev/" + string(p->d_name); 107 if (port.find("/dev/ttyUSB") == 0 || port.find("/dev/ttySerial") == 0 || port.find("/dev/cu.") == 0) { 108 newPortInfo.push_back(port); 109 auto it = std::find(serialPortInfo.begin(), serialPortInfo.end(), port); 110 if (it == serialPortInfo.end()) { 111 portChange = true; 112 WRITE_LOG(LOG_INFO, "new port:%s", port.c_str()); 113 } 114 } 115 } 116 } 117 closedir(dir); 118 } 119#endif 120 for (auto &oldPort : serialPortInfo) { 121 auto it = std::find(newPortInfo.begin(), newPortInfo.end(), oldPort); 122 if (it == newPortInfo.end()) { 123 // not found in new port list 124 // we need remove the connect info 125 serialPortRemoved.emplace_back(oldPort); 126 } 127 } 128 129 if (!portChange) { 130 // new scan empty , same as port changed 131 if (serialPortInfo.size() != newPortInfo.size()) { 132 portChange = true; 133 } 134 } 135 if (portChange) { 136 serialPortInfo.swap(newPortInfo); 137 } 138 return bRet; 139} 140 141std::string CanonicalizeSpecPath(std::string &src) { 142 char resolvedPath[PATH_MAX] = { 0 }; 143#ifdef HOST_MINGW 144 if (!_fullpath(resolvedPath, src.c_str(), PATH_MAX)) { 145 return ""; 146 } 147#else 148 if (realpath(src.c_str(), resolvedPath) == nullptr) { 149 return ""; 150 } 151#endif 152 std::string res(resolvedPath); 153 return res; 154} 155 156#ifdef HOST_MINGW 157 158static constexpr int PORT_NAME_LEN = 10; 159static constexpr int NUM = 2; 160 161HANDLE WinOpenSerialPort(std::string portName) { 162 WRITE_LOG(LOG_INFO, "WinOpenSerialPort start, portName %s", portName.c_str()); 163 TCHAR buf[PORT_NAME_LEN * NUM]; 164 #ifdef UNICODE 165 _stprintf_s(buf, MAX_PATH, _T("\\\\.\\%S"), portName.c_str()); 166 #else 167 _stprintf_s(buf, MAX_PATH, _T("\\\\.\\%s"), portName.c_str()); 168 #endif // UNICODE 169 DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED; 170 HANDLE devUartHandle = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0, NULL, 171 OPEN_EXISTING, dwFlagsAndAttributes, NULL); 172 if (devUartHandle == INVALID_HANDLE_VALUE) 173 { 174 WRITE_LOG(LOG_INFO, "CreateFile, open handle ok"); 175 } else { 176 WRITE_LOG(LOG_WARN, "CreateFile open failed"); 177 } 178 179 return devUartHandle; 180} 181 182bool WinSetSerialPort(HANDLE devUartHandle, string serialport, int byteSize, int baudRate) { 183 bool winRet = true; 184 COMMTIMEOUTS timeouts; 185 GetCommTimeouts(devUartHandle, &timeouts); 186 int interTimeout = 5; 187 timeouts.ReadIntervalTimeout = interTimeout; 188 timeouts.ReadTotalTimeoutMultiplier = 0; 189 timeouts.ReadTotalTimeoutConstant = 0; 190 timeouts.WriteTotalTimeoutMultiplier = 0; 191 timeouts.WriteTotalTimeoutConstant = 0; 192 SetCommTimeouts(devUartHandle, &timeouts); 193 constexpr int max = DEFAULT_BAUD_RATE_VALUE / 8 * 2; // 2 second buffer size 194 do { 195 if (!SetupComm(devUartHandle, max, max)) { 196 WRITE_LOG(LOG_WARN, "SetupComm %s fail, err:%lu.", serialport.c_str(), GetLastError()); 197 winRet = false; 198 break; 199 } 200 DCB dcb; 201 if (!GetCommState(devUartHandle, &dcb)) { 202 WRITE_LOG(LOG_WARN, "GetCommState %s fail, err:%lu.", serialport.c_str(), GetLastError()); 203 winRet = false; 204 } 205 dcb.DCBlength = sizeof(DCB); 206 dcb.BaudRate = baudRate; 207 dcb.Parity = 0; 208 dcb.ByteSize = byteSize; 209 dcb.StopBits = ONESTOPBIT; 210 if (!SetCommState(devUartHandle, &dcb)) { 211 WRITE_LOG(LOG_WARN, "SetCommState %s fail, err:%lu.", serialport.c_str(), GetLastError()); 212 winRet = false; 213 break; 214 } 215 if (!PurgeComm(devUartHandle, 216 PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT)) { 217 WRITE_LOG(LOG_WARN, "PurgeComm %s fail, err:%lu.", serialport.c_str(), GetLastError()); 218 winRet = false; 219 break; 220 } 221 DWORD dwError; 222 COMSTAT cs; 223 if (!ClearCommError(devUartHandle, &dwError, &cs)) { 224 WRITE_LOG(LOG_WARN, "ClearCommError %s fail, err:%lu.", serialport.c_str(), GetLastError()); 225 winRet = false; 226 break; 227 } 228 } while (false); 229 WRITE_LOG(LOG_INFO, "WinSetSerialPort ret %d\n", winRet); 230 if (!winRet) { 231 WinCloseSerialPort(devUartHandle); 232 } 233 return winRet; 234} 235 236bool WinCloseSerialPort(HANDLE &handle) { 237 WRITE_LOG(LOG_DEBUG, "CloseSerialPort"); 238 if (handle != INVALID_HANDLE_VALUE) { 239 CloseHandle(handle); 240 handle = INVALID_HANDLE_VALUE; 241 } 242 return true; 243} 244 245ssize_t WinReadUartDev(HANDLE handle, std::vector<uint8_t> &readBuf, size_t expectedSize, OVERLAPPED &overRead) { 246 ssize_t totalBytesRead = 0; 247 uint8_t uartReadBuffer[MAX_UART_SIZE_IOBUF]; 248 DWORD bytesRead = 0; 249 250 do { 251 bytesRead = 0; 252 BOOL bReadStatus = ReadFile(handle, uartReadBuffer, sizeof(uartReadBuffer), &bytesRead, &overRead); 253 if (!bReadStatus) { 254 if (GetLastError() == ERROR_IO_PENDING) { 255 bytesRead = 0; 256 DWORD dwMilliseconds = READ_GIVE_UP_TIME_OUT_TIME_MS; 257 if (expectedSize == 0) { 258 dwMilliseconds = INFINITE; 259 } 260 if (!GetOverlappedResultEx(handle, &overRead, &bytesRead, 261 dwMilliseconds, FALSE)) { 262 // wait io failed 263 DWORD error = GetLastError(); 264 if (error == ERROR_OPERATION_ABORTED) { 265 totalBytesRead += bytesRead; 266 WRITE_LOG(LOG_WARN, "%s error cancel read. %lu %zd", 267 __FUNCTION__, bytesRead, totalBytesRead); 268 return totalBytesRead; 269 } else if (error == WAIT_TIMEOUT) { 270 totalBytesRead += bytesRead; 271 WRITE_LOG(LOG_WARN, "%s error timeout. %lu %zd", 272 __FUNCTION__, bytesRead, totalBytesRead); 273 return totalBytesRead; 274 } else { 275 WRITE_LOG(LOG_WARN, "%s error wait io:%lu.", __FUNCTION__, GetLastError()); 276 } 277 return -1; 278 } 279 } else { 280 // not ERROR_IO_PENDING 281 WRITE_LOG(LOG_WARN, "%s err:%lu. ", __FUNCTION__, GetLastError()); 282 return -1; 283 } 284 } 285 if (bytesRead > 0) { 286 readBuf.insert(readBuf.end(), uartReadBuffer, uartReadBuffer + bytesRead); 287 totalBytesRead += bytesRead; 288 } 289 } while (readBuf.size() < expectedSize || bytesRead == 0); 290 return totalBytesRead; 291} 292 293ssize_t WinWriteUartDev(HANDLE handle, uint8_t *data, const size_t length, OVERLAPPED &ovWrite) { 294 ssize_t totalBytesWrite = 0; 295 do { 296 DWORD bytesWrite = 0; 297 BOOL bWriteStat = WriteFile(handle, data + totalBytesWrite, length - totalBytesWrite, &bytesWrite, &ovWrite); 298 if (!bWriteStat) { 299 if (GetLastError() == ERROR_IO_PENDING) { 300 if (!GetOverlappedResult(handle, &ovWrite, &bytesWrite, TRUE)) { 301 WRITE_LOG(LOG_WARN, "%s error wait io:%lu. bytesWrite %lu", __FUNCTION__, 302 GetLastError(), bytesWrite); 303 return -1; 304 } 305 } else { 306 WRITE_LOG(LOG_WARN, "%s err:%lu. bytesWrite %lu", __FUNCTION__, GetLastError(), 307 bytesWrite); 308 return -1; 309 } 310 } 311 totalBytesWrite += bytesWrite; 312 } while (totalBytesWrite < signed(length)); 313 return totalBytesWrite; 314} 315 316#else 317 318int GetUartSpeed(int speed) { 319 switch (speed) { 320 case UART_SPEED2400: 321 return (B2400); 322 case UART_SPEED4800: 323 return (B4800); 324 case UART_SPEED9600: 325 return (B9600); 326 case UART_SPEED115200: 327 return (B115200); 328 case UART_SPEED921600: 329 return (B921600); 330 case UART_SPEED1500000: 331 return (B1500000); 332 default: 333 return (B921600); 334 } 335} 336 337int GetUartBits(int bits) { 338 switch (bits) { 339 case UART_BIT1: 340 return (CS7); 341 case UART_BIT2: 342 return (CS8); 343 default: 344 return (CS8); 345 } 346} 347 348int OpenSerialPort(std::string portName) { 349 int uartHandle = -1; 350 if ((uartHandle = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) < 0) { 351 WRITE_LOG(LOG_WARN, "%s: cannot open uartHandle: errno=%d\n", portName.c_str(), errno); 352 return -1; 353 } 354 usleep(UART_IO_WAIT_TIME_100); 355 // cannot open with O_CLOEXEC, must fcntl 356 fcntl(uartHandle, F_SETFD, FD_CLOEXEC); 357 int flag = fcntl(uartHandle, F_GETFL); 358 if (flag < 0) { 359 WRITE_LOG(LOG_WARN, "fcntl failed: error=%d\n", errno); 360 return -1; 361 } 362 uint32_t ret = static_cast<uint32_t>(flag); 363 ret &= ~O_NONBLOCK; 364 flag &= static_cast<int>(ret); 365 fcntl(uartHandle, F_SETFL, flag); 366 367 return uartHandle; 368} 369 370#ifdef HOST_MAC 371int SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop) { 372 struct termios options, oldttys1; 373 if (tcgetattr(fd, &oldttys1) != 0) { 374 constexpr int buf_size = 1024; 375 char buf[buf_size] = { 0 }; 376 strerror_r(errno, buf, buf_size); 377 return ERR_GENERIC; 378 } 379 380 errno_t nRet = 0; 381 nRet = memcpy_s(&options, sizeof(options), &oldttys1, sizeof(options)); 382 if (nRet != EOK) { 383 return ERR_GENERIC; 384 } 385 cfmakeraw(&options); 386 options.c_cc[VMIN] = 0; 387 options.c_cc[VTIME] = 10; // 10 * 1/10 sec : 1 sec 388 389 cfsetspeed(&options, B19200); 390 options.c_cflag |= GetUartBits(nBits); // Use 8 bit words 391 options.c_cflag &= ~PARENB; 392 393 speed_t speed = nSpeed; 394 if (ioctl(fd, IOSSIOSPEED, &speed) == -1) { 395 } 396 if ((tcsetattr(fd, TCSANOW, &options)) != 0) { 397 return ERR_GENERIC; 398 } 399 if (ioctl(fd, IOSSIOSPEED, &speed) == -1) { 400 } 401 return RET_SUCCESS; 402} 403#else 404int SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop) { 405 struct termios newttys1, oldttys1; 406 if (tcgetattr(fd, &oldttys1) != 0) { 407 constexpr int buf_size = 1024; 408 char buf[buf_size] = { 0 }; 409 strerror_r(errno, buf, buf_size); 410 return ERR_GENERIC; 411 } 412 bzero(&newttys1, sizeof(newttys1)); 413 newttys1.c_cflag = GetUartSpeed(nSpeed); 414 newttys1.c_cflag |= (CLOCAL | CREAD); 415 newttys1.c_cflag &= ~CSIZE; 416 newttys1.c_lflag &= ~ICANON; 417 newttys1.c_cflag |= GetUartBits(nBits); 418 switch (nEvent) { 419 case 'O': 420 newttys1.c_cflag |= PARENB; 421 newttys1.c_iflag |= (INPCK | ISTRIP); 422 newttys1.c_cflag |= PARODD; 423 break; 424 case 'E': 425 newttys1.c_cflag |= PARENB; 426 newttys1.c_iflag |= (INPCK | ISTRIP); 427 newttys1.c_cflag &= ~PARODD; 428 break; 429 case 'N': 430 newttys1.c_cflag &= ~PARENB; 431 break; 432 default: 433 break; 434 } 435 if (nStop == UART_STOP1) { 436 newttys1.c_cflag &= ~CSTOPB; 437 } else if (nStop == UART_STOP2) { 438 newttys1.c_cflag |= CSTOPB; 439 } 440 newttys1.c_cc[VTIME] = 0; 441 newttys1.c_cc[VMIN] = 0; 442 if (tcflush(fd, TCIOFLUSH)) { 443 return ERR_GENERIC; 444 } 445 if ((tcsetattr(fd, TCSANOW, &newttys1)) != 0) { 446 return ERR_GENERIC; 447 } 448 return ERR_SUCCESS; 449} 450#endif 451 452ssize_t ReadUartDev(int handle, std::vector<uint8_t> &readBuf, size_t expectedSize) { 453 ssize_t totalBytesRead = 0; 454 uint8_t uartReadBuffer[MAX_UART_SIZE_IOBUF]; 455 ssize_t bytesRead = 0; 456 457 do { 458 bytesRead = 0; 459 int ret = 0; 460 fd_set readFds; 461 FD_ZERO(&readFds); 462 FD_SET(handle, &readFds); 463 const constexpr int msTous = 1000; 464 const constexpr int sTous = 1000 * msTous; 465 struct timeval tv; 466 tv.tv_sec = 0; 467 468 if (expectedSize == 0) { 469 tv.tv_usec = WAIT_RESPONSE_TIME_OUT_MS * msTous; 470 tv.tv_sec = tv.tv_usec / sTous; 471 tv.tv_usec = tv.tv_usec % sTous; 472#ifdef HDC_HOST 473 // only host side need this 474 // in this caes 475 // We need a way to exit from the select for the destruction and recovery of the 476 // serial port read thread. 477 ret = select(handle + 1, &readFds, nullptr, nullptr, &tv); 478#else 479 ret = select(handle + 1, &readFds, nullptr, nullptr, nullptr); 480#endif 481 } else { 482 // when we have expect size , we need timeout for link data drop issue 483 tv.tv_usec = READ_GIVE_UP_TIME_OUT_TIME_MS * msTous; 484 tv.tv_sec = tv.tv_usec / sTous; 485 tv.tv_usec = tv.tv_usec % sTous; 486 ret = select(handle + 1, &readFds, nullptr, nullptr, &tv); 487 } 488 if (ret == 0 and expectedSize == 0) { 489 // no expect but timeout 490 if (g_ioCancel) { 491 g_ioCancel = true; 492 return totalBytesRead; 493 } else { 494 continue; 495 } 496 } else if (ret == 0) { 497 // we expected some byte , but not arrive before timeout 498 return totalBytesRead; 499 } else if (ret < 0) { 500 return -1; // wait failed. 501 } else { 502 // select > 0 503 size_t maxReadSize = expectedSize - static_cast<size_t>(totalBytesRead); 504 if (maxReadSize > MAX_UART_SIZE_IOBUF) { 505 maxReadSize = MAX_UART_SIZE_IOBUF; 506 } 507 bytesRead = read(handle, uartReadBuffer, maxReadSize); 508 if (bytesRead <= 0) { 509 // read failed ! 510 return -1; 511 } 512 } 513 if (bytesRead > 0) { 514 readBuf.insert(readBuf.end(), uartReadBuffer, uartReadBuffer + bytesRead); 515 totalBytesRead += bytesRead; 516 } 517 } while (readBuf.size() < expectedSize or bytesRead == 0); // if caller know how many bytes it want 518 return totalBytesRead; 519} 520 521ssize_t WriteUartDev(int handle, uint8_t *data, const size_t length) { 522 ssize_t totalBytesWrite = 0; 523 do { 524 ssize_t bytesWrite = 0; 525 bytesWrite = write(handle, data + totalBytesWrite, length - totalBytesWrite); 526 if (bytesWrite < 0) { 527 if (errno == EINTR or errno == EAGAIN) { 528 continue; 529 } else { 530 // we don't know how to recory in this function 531 // need reopen device ? 532 constexpr int buf_size = 1024; 533 char buf[buf_size] = { 0 }; 534 strerror_r(errno, buf, buf_size); 535 return -1; 536 } 537 } else { 538 // waits until all output written to the object referred to by fd has been transmitted. 539 tcdrain(handle); 540 } 541 totalBytesWrite += bytesWrite; 542 } while (totalBytesWrite < signed(length)); 543 544 return totalBytesWrite; 545} 546 547bool CloseSerialPort(int &handle) { 548 if (handle != -1) 549 { 550 return CloseFd(handle) >= 0; 551 } else { 552 return true; 553 } 554} 555 556int CloseFd(int &fd) { 557 int rc = 0; 558#ifndef HDC_HOST 559#endif 560 if (fd > 0) { 561 rc = close(fd); 562 if (rc < 0) { 563 char buffer[Hdc::BUF_SIZE_DEFAULT] = { 0 }; 564#ifdef _WIN32 565 strerror_s(buffer, Hdc::BUF_SIZE_DEFAULT, errno); 566#else 567 strerror_r(errno, buffer, Hdc::BUF_SIZE_DEFAULT); 568#endif 569 } else { 570 fd = -1; 571 } 572 } 573 return rc; 574} 575 576#endif 577