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
22 using namespace std;
23 using namespace Hdc;
24
25 bool g_ioCancel = false;
26
27 // review why not use QueryDosDevice ?
EnumSerialPort(bool & portChange)28 bool 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 while (dir != nullptr && ((p = readdir(dir)) != nullptr)) {
100 #ifdef HOST_LINUX
101 if (p->d_name[0] != '.' && string(p->d_name).find("tty") != std::string::npos) {
102 #else
103 if (p->d_name[0] != '.' && string(p->d_name).find("serial") != std::string::npos) {
104 #endif
105 string port = "/dev/" + string(p->d_name);
106 if (port.find("/dev/ttyUSB") == 0 || port.find("/dev/ttySerial") == 0 || port.find("/dev/cu.") == 0) {
107 newPortInfo.push_back(port);
108 auto it = std::find(serialPortInfo.begin(), serialPortInfo.end(), port);
109 if (it == serialPortInfo.end()) {
110 portChange = true;
111 WRITE_LOG(LOG_INFO, "new port:%s", port.c_str());
112 }
113 }
114 }
115 }
116 if (dir != nullptr) {
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
141 std::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
158 static constexpr int PORT_NAME_LEN = 10;
159 static constexpr int NUM = 2;
160
161 HANDLE 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
182 bool 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
236 bool 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
245 ssize_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
293 ssize_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
318 int 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
337 int 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
348 int 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 flag &= ~O_NONBLOCK;
359 fcntl(uartHandle, F_SETFL, flag);
360
361 return uartHandle;
362 }
363
364 #ifdef HOST_MAC
365 int SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop) {
366 struct termios options, oldttys1;
367 if (tcgetattr(fd, &oldttys1) != 0) {
368 constexpr int buf_size = 1024;
369 char buf[buf_size] = { 0 };
370 strerror_r(errno, buf, buf_size);
371 return ERR_GENERIC;
372 }
373
374 errno_t nRet = 0;
375 nRet = memcpy_s(&options, sizeof(options), &oldttys1, sizeof(options));
376 if (nRet != EOK) {
377 return ERR_GENERIC;
378 }
379 cfmakeraw(&options);
380 options.c_cc[VMIN] = 0;
381 options.c_cc[VTIME] = 10; // 10 * 1/10 sec : 1 sec
382
383 cfsetspeed(&options, B19200);
384 options.c_cflag |= GetUartBits(nBits); // Use 8 bit words
385 options.c_cflag &= ~PARENB;
386
387 speed_t speed = nSpeed;
388 if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
389 }
390 if ((tcsetattr(fd, TCSANOW, &options)) != 0) {
391 return ERR_GENERIC;
392 }
393 if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
394 }
395 return RET_SUCCESS;
396 }
397 #else
398 int SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop) {
399 struct termios newttys1, oldttys1;
400 if (tcgetattr(fd, &oldttys1) != 0) {
401 constexpr int buf_size = 1024;
402 char buf[buf_size] = { 0 };
403 strerror_r(errno, buf, buf_size);
404 return ERR_GENERIC;
405 }
406 bzero(&newttys1, sizeof(newttys1));
407 newttys1.c_cflag = GetUartSpeed(nSpeed);
408 newttys1.c_cflag |= (CLOCAL | CREAD);
409 newttys1.c_cflag &= ~CSIZE;
410 newttys1.c_lflag &= ~ICANON;
411 newttys1.c_cflag |= GetUartBits(nBits);
412 switch (nEvent) {
413 case 'O':
414 newttys1.c_cflag |= PARENB;
415 newttys1.c_iflag |= (INPCK | ISTRIP);
416 newttys1.c_cflag |= PARODD;
417 break;
418 case 'E':
419 newttys1.c_cflag |= PARENB;
420 newttys1.c_iflag |= (INPCK | ISTRIP);
421 newttys1.c_cflag &= ~PARODD;
422 break;
423 case 'N':
424 newttys1.c_cflag &= ~PARENB;
425 break;
426 default:
427 break;
428 }
429 if (nStop == UART_STOP1) {
430 newttys1.c_cflag &= ~CSTOPB;
431 } else if (nStop == UART_STOP2) {
432 newttys1.c_cflag |= CSTOPB;
433 }
434 newttys1.c_cc[VTIME] = 0;
435 newttys1.c_cc[VMIN] = 0;
436 if (tcflush(fd, TCIOFLUSH)) {
437 return ERR_GENERIC;
438 }
439 if ((tcsetattr(fd, TCSANOW, &newttys1)) != 0) {
440 return ERR_GENERIC;
441 }
442 return ERR_SUCCESS;
443 }
444 #endif
445
446 ssize_t ReadUartDev(int handle, std::vector<uint8_t> &readBuf, size_t expectedSize) {
447 ssize_t totalBytesRead = 0;
448 uint8_t uartReadBuffer[MAX_UART_SIZE_IOBUF];
449 ssize_t bytesRead = 0;
450
451 do {
452 bytesRead = 0;
453 int ret = 0;
454 fd_set readFds;
455 FD_ZERO(&readFds);
456 FD_SET(handle, &readFds);
457 const constexpr int msTous = 1000;
458 const constexpr int sTous = 1000 * msTous;
459 struct timeval tv;
460 tv.tv_sec = 0;
461
462 if (expectedSize == 0) {
463 tv.tv_usec = WAIT_RESPONSE_TIME_OUT_MS * msTous;
464 tv.tv_sec = tv.tv_usec / sTous;
465 tv.tv_usec = tv.tv_usec % sTous;
466 #ifdef HDC_HOST
467 // only host side need this
468 // in this caes
469 // We need a way to exit from the select for the destruction and recovery of the
470 // serial port read thread.
471 ret = select(handle + 1, &readFds, nullptr, nullptr, &tv);
472 #else
473 ret = select(handle + 1, &readFds, nullptr, nullptr, nullptr);
474 #endif
475 } else {
476 // when we have expect size , we need timeout for link data drop issue
477 tv.tv_usec = READ_GIVE_UP_TIME_OUT_TIME_MS * msTous;
478 tv.tv_sec = tv.tv_usec / sTous;
479 tv.tv_usec = tv.tv_usec % sTous;
480 ret = select(handle + 1, &readFds, nullptr, nullptr, &tv);
481 }
482 if (ret == 0 and expectedSize == 0) {
483 // no expect but timeout
484 if (g_ioCancel) {
485 g_ioCancel = true;
486 return totalBytesRead;
487 } else {
488 continue;
489 }
490 } else if (ret == 0) {
491 // we expected some byte , but not arrive before timeout
492 return totalBytesRead;
493 } else if (ret < 0) {
494 return -1; // wait failed.
495 } else {
496 // select > 0
497 size_t maxReadSize = expectedSize - totalBytesRead;
498 if (maxReadSize > MAX_UART_SIZE_IOBUF) {
499 maxReadSize = MAX_UART_SIZE_IOBUF;
500 }
501 bytesRead = read(handle, uartReadBuffer, maxReadSize);
502 if (bytesRead <= 0) {
503 // read failed !
504 return -1;
505 }
506 }
507 if (bytesRead > 0) {
508 readBuf.insert(readBuf.end(), uartReadBuffer, uartReadBuffer + bytesRead);
509 totalBytesRead += bytesRead;
510 }
511 } while (readBuf.size() < expectedSize or bytesRead == 0); // if caller know how many bytes it want
512 return totalBytesRead;
513 }
514
515 ssize_t WriteUartDev(int handle, uint8_t *data, const size_t length) {
516 ssize_t totalBytesWrite = 0;
517 do {
518 ssize_t bytesWrite = 0;
519 bytesWrite = write(handle, data + totalBytesWrite, length - totalBytesWrite);
520 if (bytesWrite < 0) {
521 if (errno == EINTR or errno == EAGAIN) {
522 continue;
523 } else {
524 // we don't know how to recory in this function
525 // need reopen device ?
526 constexpr int buf_size = 1024;
527 char buf[buf_size] = { 0 };
528 strerror_r(errno, buf, buf_size);
529 return -1;
530 }
531 } else {
532 // waits until all output written to the object referred to by fd has been transmitted.
533 tcdrain(handle);
534 }
535 totalBytesWrite += bytesWrite;
536 } while (totalBytesWrite < signed(length));
537
538 return totalBytesWrite;
539 }
540
541 bool CloseSerialPort(int &handle) {
542 if (handle != -1)
543 {
544 return CloseFd(handle) >= 0;
545 } else {
546 return true;
547 }
548 }
549
550 int CloseFd(int &fd) {
551 int rc = 0;
552 #ifndef HDC_HOST
553 #endif
554 if (fd > 0) {
555 rc = close(fd);
556 if (rc < 0) {
557 char buffer[Hdc::BUF_SIZE_DEFAULT] = { 0 };
558 #ifdef _WIN32
559 strerror_s(buffer, Hdc::BUF_SIZE_DEFAULT, errno);
560 #else
561 strerror_r(errno, buffer, Hdc::BUF_SIZE_DEFAULT);
562 #endif
563 } else {
564 fd = -1;
565 }
566 }
567 return rc;
568 }
569
570 #endif
571