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