xref: /developtools/hdc/src/common/uart.cpp (revision cc290419)
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 "uart.h"
19#ifdef HOST_MAC
20#include <fcntl.h>
21#include <sys/ioctl.h>
22#include <IOKit/serial/ioss.h>
23#define B1500000 1500000
24#define B921600 921600
25#endif
26
27using namespace std::chrono;
28namespace Hdc {
29ExternInterface HdcUARTBase::defaultInterface;
30
31void ExternInterface::SetTcpOptions(uv_tcp_t *tcpHandle)
32{
33    return Base::SetTcpOptions(tcpHandle);
34}
35
36int ExternInterface::SendToStream(uv_stream_t *handleStream, const uint8_t *buf, const int len)
37{
38    return Base::SendToStream(handleStream, buf, len);
39}
40
41int ExternInterface::SendToPollFd(int fd, const uint8_t *buf, const int len)
42{
43    return Base::SendToPollFd(fd, buf, len);
44}
45
46int ExternInterface::UvTcpInit(uv_loop_t *loop, uv_tcp_t *tcp, int socketFd)
47{
48    if (uv_tcp_init(loop, tcp) == 0) {
49        return uv_tcp_open(tcp, socketFd);
50    } else {
51        return -1;
52    }
53}
54
55int ExternInterface::UvRead(uv_stream_t *stream, uv_alloc_cb allocCallBack, uv_read_cb readCallBack)
56{
57    return uv_read_start(stream, allocCallBack, readCallBack);
58}
59
60int ExternInterface::StartWorkThread(uv_loop_t *loop, uv_work_cb pFuncWorkThread,
61                                     uv_after_work_cb pFuncAfterThread, void *pThreadData)
62{
63    return Base::StartWorkThread(loop, pFuncWorkThread, pFuncAfterThread, pThreadData);
64}
65
66void ExternInterface::TryCloseHandle(const uv_handle_t *handle, uv_close_cb closeCallBack)
67{
68    return Base::TryCloseHandle(handle, closeCallBack);
69}
70
71bool ExternInterface::TimerUvTask(uv_loop_t *loop, void *data, uv_timer_cb cb)
72{
73    return Base::TimerUvTask(loop, data, cb);
74}
75bool ExternInterface::UvTimerStart(uv_timer_t *handle, uv_timer_cb cb, uint64_t timeout,
76                                   uint64_t repeat)
77{
78    return uv_timer_start(handle, cb, timeout, repeat);
79}
80
81bool ExternInterface::DelayDo(uv_loop_t *loop, const int delayMs, const uint8_t flag, string msg,
82                              void *data, DelayCB cb)
83{
84    return Base::DelayDo(loop, delayMs, flag, msg, data, cb);
85}
86
87HdcUARTBase::HdcUARTBase(HdcSessionBase &sessionBaseIn, ExternInterface &interfaceIn)
88    : externInterface(interfaceIn), sessionBase(sessionBaseIn)
89{
90    uartOpened = false;
91}
92
93HdcUARTBase::~HdcUARTBase(void) {}
94
95#ifndef _WIN32
96int HdcUARTBase::GetUartSpeed(int speed)
97{
98    switch (speed) {
99        case UART_SPEED2400:
100            return (B2400);
101            break;
102        case UART_SPEED4800:
103            return (B4800);
104            break;
105        case UART_SPEED9600:
106            return (B9600);
107            break;
108        case UART_SPEED115200:
109            return (B115200);
110            break;
111        case UART_SPEED921600:
112            return (B921600);
113            break;
114        case UART_SPEED1500000:
115            return (B1500000);
116        default:
117            return (B921600);
118            break;
119    }
120}
121int HdcUARTBase::GetUartBits(int bits)
122{
123    switch (bits) {
124        case UART_BIT1:
125            return (CS7);
126            break;
127        case UART_BIT2:
128            return (CS8);
129            break;
130        default:
131            return (CS8);
132            break;
133    }
134}
135#if defined(HOST_MAC)
136int HdcUARTBase::SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop)
137{
138    WRITE_LOG(LOG_DEBUG, "mac SetSerial rate = %d", nSpeed);
139    struct termios options;
140    struct termios oldttys1;
141    if (tcgetattr(fd, &oldttys1) != 0) {
142        constexpr int bufSize = 1024;
143        char buf[bufSize] = { 0 };
144        strerror_r(errno, buf, bufSize);
145        WRITE_LOG(LOG_DEBUG, "tcgetattr failed with %s\n", buf);
146        return ERR_GENERIC;
147    }
148
149    if (memcpy_s(&options, sizeof(options), &oldttys1, sizeof(options)) != EOK) {
150        return ERR_GENERIC;
151    }
152    cfmakeraw(&options);
153    options.c_cc[VMIN] = 0;
154    options.c_cc[VTIME] = 10; // 10 * 1/10 sec : 1 sec
155
156    cfsetspeed(&options, B19200);
157    options.c_cflag |= GetUartBits(nBits); // Use 8 bit words
158    options.c_cflag &= ~PARENB;
159
160    speed_t speed = nSpeed;
161    if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
162        WRITE_LOG(LOG_DEBUG, "set speed errno %d", errno);
163    }
164    if ((tcsetattr(fd, TCSANOW, &options)) != 0) {
165        WRITE_LOG(LOG_DEBUG, "com set error errno = %d", errno);
166        return ERR_GENERIC;
167    }
168    if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
169        WRITE_LOG(LOG_DEBUG, "set speed errno %d", errno);
170    }
171    WRITE_LOG(LOG_DEBUG, " SetSerial OK rate = %d", nSpeed);
172    return RET_SUCCESS;
173}
174#else
175int HdcUARTBase::SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop)
176{
177    struct termios newttys1;
178    struct termios oldttys1;
179    if (tcgetattr(fd, &oldttys1) != 0) {
180        constexpr int bufSize = 1024;
181        char buf[bufSize] = { 0 };
182        strerror_r(errno, buf, bufSize);
183        WRITE_LOG(LOG_DEBUG, "tcgetattr failed with %s\n", buf);
184        return ERR_GENERIC;
185    }
186    bzero(&newttys1, sizeof(newttys1));
187    newttys1.c_cflag = GetUartSpeed(nSpeed);
188    newttys1.c_cflag |= (CLOCAL | CREAD);
189    newttys1.c_cflag &= ~CSIZE;
190    newttys1.c_lflag &= ~ICANON;
191    newttys1.c_cflag |= GetUartBits(nBits);
192    switch (nEvent) {
193        case 'O':
194            newttys1.c_cflag |= PARENB;
195            newttys1.c_iflag |= (INPCK | ISTRIP);
196            newttys1.c_cflag |= PARODD;
197            break;
198        case 'E':
199            newttys1.c_cflag |= PARENB;
200            newttys1.c_iflag |= (INPCK | ISTRIP);
201            newttys1.c_cflag &= ~PARODD;
202            break;
203        case 'N':
204            newttys1.c_cflag &= ~PARENB;
205            break;
206        default:
207            break;
208    }
209    if (nStop == UART_STOP1) {
210        newttys1.c_cflag &= ~CSTOPB;
211    } else if (nStop == UART_STOP2) {
212        newttys1.c_cflag |= CSTOPB;
213    }
214    newttys1.c_cc[VTIME] = 0;
215    newttys1.c_cc[VMIN] = 0;
216    if (tcflush(fd, TCIOFLUSH)) {
217        WRITE_LOG(LOG_DEBUG, " tcflush error.");
218        return ERR_GENERIC;
219    }
220    if ((tcsetattr(fd, TCSANOW, &newttys1)) != 0) {
221        WRITE_LOG(LOG_DEBUG, "com set error errno = %d", errno);
222        return ERR_GENERIC;
223    }
224    WRITE_LOG(LOG_DEBUG, " SetSerial OK rate = %d", nSpeed);
225    return RET_SUCCESS;
226}
227#endif
228#endif // _WIN32
229
230ssize_t HdcUARTBase::ReadUartDev(std::vector<uint8_t> &readBuf, size_t expectedSize, HdcUART &uart)
231{
232    ssize_t totalBytesRead = 0;
233    uint8_t uartReadBuffer[MAX_UART_SIZE_IOBUF];
234#ifdef _WIN32
235    DWORD bytesRead = 0;
236#else
237    ssize_t bytesRead = 0;
238#endif
239    do {
240        bytesRead = 0;
241#ifdef _WIN32
242        BOOL bReadStatus = ReadFile(uart.devUartHandle, uartReadBuffer, sizeof(uartReadBuffer),
243                                    &bytesRead, &uart.ovRead);
244        if (!bReadStatus) {
245            if (GetLastError() == ERROR_IO_PENDING) {
246                bytesRead = 0;
247                DWORD dwMilliseconds = READ_GIVE_UP_TIME_OUT_TIME_MS;
248                if (expectedSize == 0) {
249                    dwMilliseconds = INFINITE;
250                }
251                if (!GetOverlappedResultEx(uart.devUartHandle, &uart.ovRead, &bytesRead,
252                                           dwMilliseconds, FALSE)) {
253                    // wait io failed
254                    DWORD error = GetLastError();
255                    if (error == ERROR_OPERATION_ABORTED) {
256                        totalBytesRead += bytesRead;
257                        WRITE_LOG(LOG_DEBUG, "%s error cancel read. %u %zd", __FUNCTION__,
258                                  bytesRead, totalBytesRead);
259                        // Generally speaking, this is the cacnel caused by freesession
260                        // Returning allows the outer read loop to run again. This checks the exit
261                        // condition.
262                        return totalBytesRead;
263                    } else if (error == WAIT_TIMEOUT) {
264                        totalBytesRead += bytesRead;
265                        WRITE_LOG(LOG_DEBUG, "%s error timeout. %u %zd", __FUNCTION__, bytesRead,
266                                  totalBytesRead);
267                        return totalBytesRead;
268                    } else {
269                        WRITE_LOG(LOG_DEBUG, "%s error wait io:%d.", __FUNCTION__, GetLastError());
270                    }
271                    return -1;
272                }
273            } else {
274                // not ERROR_IO_PENDING
275                WRITE_LOG(LOG_DEBUG, "%s  err:%d. ", __FUNCTION__, GetLastError());
276                return -1;
277            }
278        }
279#else
280        int ret = 0;
281        fd_set readFds;
282        FD_ZERO(&readFds);
283        FD_SET(uart.devUartHandle, &readFds);
284        const constexpr int msTous = 1000;
285        const constexpr int sTous = 1000 * msTous;
286        struct timeval tv;
287        tv.tv_sec = 0;
288
289        if (expectedSize == 0) {
290            tv.tv_usec = WAIT_RESPONSE_TIME_OUT_MS * msTous;
291            tv.tv_sec = tv.tv_usec / sTous;
292            tv.tv_usec = tv.tv_usec % sTous;
293            WRITE_LOG(LOG_DEBUG, "time  =  %d %d", tv.tv_sec, tv.tv_sec);
294#ifdef HDC_HOST
295            // only host side need this
296            // in this caes
297            // We need a way to exit from the select for the destruction and recovery of the
298            // serial port read thread.
299            ret = select(uart.devUartHandle + 1, &readFds, nullptr, nullptr, &tv);
300#else
301            ret = select(uart.devUartHandle + 1, &readFds, nullptr, nullptr, nullptr);
302#endif
303        } else {
304            // when we have expect size , we need timeout for link data drop issue
305            tv.tv_usec = READ_GIVE_UP_TIME_OUT_TIME_MS * msTous;
306            tv.tv_sec = tv.tv_usec / sTous;
307            tv.tv_usec = tv.tv_usec % sTous;
308            ret = select(uart.devUartHandle + 1, &readFds, nullptr, nullptr, &tv);
309        }
310        if (ret == 0 and expectedSize == 0) {
311            // no expect but timeout
312            if (uart.ioCancel) {
313                WRITE_LOG(LOG_DEBUG, "%s:uart select time out and io cancel", __FUNCTION__);
314                uart.ioCancel = true;
315                return totalBytesRead;
316            } else {
317                continue;
318            }
319        } else if (ret == 0) {
320            WRITE_LOG(LOG_DEBUG, "%s:uart select time out!", __FUNCTION__);
321            // we expected some byte , but not arrive before timeout
322            return totalBytesRead;
323        } else if (ret < 0) {
324            WRITE_LOG(LOG_DEBUG, "%s:uart select error! %d", __FUNCTION__, errno);
325            return -1; // wait failed.
326        } else {
327            // select > 0
328            bytesRead = read(uart.devUartHandle, uartReadBuffer, sizeof(uartReadBuffer));
329            if (bytesRead <= 0) {
330                // read failed !
331                WRITE_LOG(LOG_WARN, "%s:read failed! %zd:%d", __FUNCTION__, bytesRead, errno);
332                return -1;
333            }
334        }
335#endif
336        if (bytesRead > 0) {
337            readBuf.insert(readBuf.end(), uartReadBuffer, uartReadBuffer + bytesRead);
338            totalBytesRead += bytesRead;
339        }
340    } while (readBuf.size() < expectedSize or
341             bytesRead == 0); // if caller know how many bytes it want
342    return totalBytesRead;
343}
344
345ssize_t HdcUARTBase::WriteUartDev(uint8_t *data, const size_t length, HdcUART &uart)
346{
347    ssize_t totalBytesWrite = 0;
348    WRITE_LOG(LOG_ALL, "%s %d data %x %x", __FUNCTION__, length, *(data + sizeof(UartHead)),
349              *(data + sizeof(UartHead) + 1));
350    do {
351#ifdef _WIN32
352        DWORD bytesWrite = 0;
353        BOOL bWriteStat = WriteFile(uart.devUartHandle, data + totalBytesWrite,
354                                    length - totalBytesWrite, &bytesWrite, &uart.ovWrite);
355        if (!bWriteStat) {
356            if (GetLastError() == ERROR_IO_PENDING) {
357                if (!GetOverlappedResult(uart.devUartHandle, &uart.ovWrite, &bytesWrite, TRUE)) {
358                    WRITE_LOG(LOG_DEBUG, "%s error wait io:%d. bytesWrite %zu", __FUNCTION__,
359                              GetLastError(), bytesWrite);
360                    return -1;
361                }
362            } else {
363                WRITE_LOG(LOG_DEBUG, "%s err:%d. bytesWrite %zu", __FUNCTION__, GetLastError(),
364                          bytesWrite);
365                return -1;
366            }
367        }
368#else // not win32
369        ssize_t bytesWrite = 0;
370        bytesWrite = write(uart.devUartHandle, data + totalBytesWrite, length - totalBytesWrite);
371        if (bytesWrite < 0) {
372            if (errno == EINTR or errno == EAGAIN) {
373                WRITE_LOG(LOG_WARN, "EINTR/EAGAIN, try again");
374                continue;
375            } else {
376                // we don't know how to recory in this function
377                // need reopen device ?
378                constexpr int bufSize = 1024;
379                char buf[bufSize] = { 0 };
380                strerror_r(errno, buf, bufSize);
381                WRITE_LOG(LOG_FATAL, "write fatal errno %d:%s", errno, buf);
382                return -1;
383            }
384        } else {
385            // waits until all output written to the object referred to by fd has been transmitted.
386            tcdrain(uart.devUartHandle);
387        }
388#endif
389        totalBytesWrite += bytesWrite;
390    } while (totalBytesWrite < signed(length));
391
392    return totalBytesWrite;
393}
394
395int HdcUARTBase::UartToHdcProtocol(uv_stream_t *stream, uint8_t *data, int dataSize)
396{
397    HSession hSession = (HSession)stream->data;
398    unsigned int fd = hSession->dataFd[STREAM_MAIN];
399    fd_set fdSet;
400    struct timeval timeout = {3, 0};
401    FD_ZERO(&fdSet);
402    FD_SET(fd, &fdSet);
403    int index = 0;
404    int childRet = 0;
405
406    while (index < dataSize) {
407        childRet = select(fd + 1, NULL, &fdSet, NULL, &timeout);
408        if (childRet <= 0) {
409            constexpr int bufSize = 1024;
410            char buf[bufSize] = { 0 };
411#ifdef _WIN32
412            strerror_s(buf, bufSize, errno);
413#else
414            strerror_r(errno, buf, bufSize);
415#endif
416            WRITE_LOG(LOG_FATAL, "%s select error:%d [%s][%d]", __FUNCTION__, errno,
417                      buf, childRet);
418            break;
419        }
420        childRet = send(fd, (const char *)data + index, dataSize - index, 0);
421        if (childRet < 0) {
422            constexpr int bufSize = 1024;
423            char buf[bufSize] = { 0 };
424#ifdef _WIN32
425            strerror_s(buf, bufSize, errno);
426#else
427            strerror_r(errno, buf, bufSize);
428#endif
429            WRITE_LOG(LOG_FATAL, "%s senddata err:%d [%s]", __FUNCTION__, errno, buf);
430            break;
431        }
432        index += childRet;
433    }
434    if (index != dataSize) {
435        WRITE_LOG(LOG_FATAL, "%s partialsenddata err:%d [%d]", __FUNCTION__, index, dataSize);
436        return ERR_IO_FAIL;
437    }
438    return index;
439}
440
441RetErrCode HdcUARTBase::DispatchToWorkThread(HSession hSession, uint8_t *readBuf, int readBytes)
442{
443    if (hSession == nullptr) {
444        return ERR_SESSION_NOFOUND;
445    }
446    if (!UartSendToHdcStream(hSession, readBuf, readBytes)) {
447        return ERR_IO_FAIL;
448    }
449    return RET_SUCCESS;
450}
451
452size_t HdcUARTBase::PackageProcess(vector<uint8_t> &data, HSession hSession)
453{
454    while (data.size() >= sizeof(UartHead)) {
455        // is size more than one head
456        size_t packetSize = 0;
457        uint32_t sessionId = 0;
458        uint32_t packageIndex = 0;
459        // we erase all buffer. wait next read.
460        if (ValidateUartPacket(data, sessionId, packageIndex, packetSize) != RET_SUCCESS) {
461            WRITE_LOG(LOG_WARN, "%s package error. clean the read buffer.", __FUNCTION__);
462            data.clear();
463        } else if (packetSize == sizeof(UartHead)) {
464            // nothing need to send, this is a head only package
465            // only used in link layer
466            WRITE_LOG(LOG_ALL, "%s headonly Package(%zu). dont send to session, erase it",
467                      __FUNCTION__, packetSize);
468        } else {
469            // at least we got one package
470            // if the size of package have all received ?
471            if (data.size() >= packetSize) {
472                // send the data to logic level (link to logic)
473                if (hSession == nullptr) {
474#ifdef HDC_HOST
475                    hSession = GetSession(sessionId);
476#else
477                    // for daemon side we can make a new session for it
478                    hSession = GetSession(sessionId, true);
479#endif
480                }
481                if (hSession == nullptr) {
482                    WRITE_LOG(LOG_WARN, "%s have not found session (%u). skip it", __FUNCTION__, sessionId);
483                } else {
484                    if (hSession->hUART->dispatchedPackageIndex == packageIndex) {
485                        // we need check if the duplication package we have already send
486                        WRITE_LOG(LOG_WARN, "%s dup package %u, skip send to session logic",
487                                  __FUNCTION__, packageIndex);
488                    } else {
489                        // update the last package we will send to hdc
490                        hSession->hUART->dispatchedPackageIndex = packageIndex;
491                        RetErrCode ret = DispatchToWorkThread(hSession, data.data(), packetSize);
492                        if (ret == RET_SUCCESS) {
493                            WRITE_LOG(LOG_DEBUG, "%s DispatchToWorkThread successful",
494                                      __FUNCTION__);
495                        } else {
496                            // send to logic failed.
497                            // this kind of issue unable handle in link layer
498                            WRITE_LOG(LOG_FATAL,
499                                      "%s DispatchToWorkThread fail %d. request free session in "
500                                      "other side",
501                                      __FUNCTION__, ret);
502                            ResponseUartTrans(hSession->sessionId, ++hSession->hUART->packageIndex,
503                                              PKG_OPTION_FREE);
504                        }
505                    }
506                }
507            } else {
508                WRITE_LOG(LOG_DEBUG, "%s valid package, however size not enough. expect %zu",
509                          __FUNCTION__, packetSize);
510                return packetSize;
511            }
512        }
513
514        if (data.size() >= packetSize) {
515            data.erase(data.begin(), data.begin() + packetSize);
516        } else {
517            // dont clean , should merge with next package
518        }
519        WRITE_LOG(LOG_DEBUG, "PackageProcess data.size():%d left", data.size());
520    }
521    // if we have at least one byte, we think there should be a head
522    return data.size() > 1 ? sizeof(UartHead) : 0;
523}
524
525bool HdcUARTBase::SendUARTRaw(HSession hSession, uint8_t *data, const size_t length)
526{
527    struct UartHead *uartHeader = (struct UartHead *)data;
528#ifndef HDC_HOST
529    // review nobody can plug out the daemon uart , if we still need split write in daemon side?
530    HdcUART deamonUart;
531    deamonUart.devUartHandle = uartHandle;
532    if (uartHeader->IsResponsePackage()) {
533        // for the response package and in daemon side,
534        // we dont need session info
535        ssize_t sendBytes = WriteUartDev(data, length, deamonUart);
536        return sendBytes > 0;
537    }
538#endif
539
540    // for normal package
541    if (hSession == nullptr) {
542        hSession = GetSession(uartHeader->sessionId);
543        if (hSession == nullptr) {
544            // session is not found
545            WRITE_LOG(LOG_WARN, "%s hSession not found:%zu", __FUNCTION__, uartHeader->sessionId);
546            return false;
547        }
548    }
549    hSession->ref++;
550    WRITE_LOG(LOG_DEBUG, "%s length:%d", __FUNCTION__, length);
551#ifdef HDC_HOST
552    ssize_t sendBytes = WriteUartDev(data, length, *hSession->hUART);
553#else
554    ssize_t sendBytes = WriteUartDev(data, length, deamonUart);
555#endif
556    WRITE_LOG(LOG_DEBUG, "%s sendBytes %zu", __FUNCTION__, sendBytes);
557    if (sendBytes < 0) {
558        WRITE_LOG(LOG_DEBUG, "%s send fail. try to freesession", __FUNCTION__);
559        OnTransferError(hSession);
560    }
561    hSession->ref--;
562    return sendBytes > 0;
563}
564
565// this function will not check the data correct again
566// just send the data to hdc session side
567bool HdcUARTBase::UartSendToHdcStream(HSession hSession, uint8_t *data, size_t size)
568{
569    WRITE_LOG(LOG_DEBUG, "%s send to session %s package size %zu", __FUNCTION__,
570              hSession->ToDebugString().c_str(), size);
571
572    int ret = RET_SUCCESS;
573
574    if (size < sizeof(UartHead)) {
575        WRITE_LOG(LOG_FATAL, "%s buf size too small %zu", __FUNCTION__, size);
576        return ERR_BUF_SIZE;
577    }
578
579    UartHead *head = reinterpret_cast<UartHead *>(data);
580    WRITE_LOG(LOG_DEBUG, "%s uartHeader:%s data: %x %x", __FUNCTION__,
581              head->ToDebugString().c_str(), *(data + sizeof(UartHead)),
582              *(data + sizeof(UartHead) + 1));
583
584    // review need check logic again here or err process
585    if (head->sessionId != hSession->sessionId) {
586        if (hSession->serverOrDaemon && !hSession->hUART->resetIO) {
587            WRITE_LOG(LOG_FATAL, "%s sessionId not matched, reset sessionId:%d.", __FUNCTION__,
588                      head->sessionId);
589            SendUartSoftReset(hSession, head->sessionId);
590            hSession->hUART->resetIO = true;
591            ret = ERR_IO_SOFT_RESET;
592            // dont break ,we need rease these data in recv buffer
593        }
594    } else {
595        //  data to session
596        hSession->hUART->streamSize += head->dataSize; // this is only for debug,
597        WRITE_LOG(LOG_ALL, "%s stream wait session read size: %zu", __FUNCTION__,
598                  hSession->hUART->streamSize.load());
599        if (UartToHdcProtocol(reinterpret_cast<uv_stream_t *>(&hSession->dataPipe[STREAM_MAIN]),
600                              data + sizeof(UartHead), head->dataSize) < 0) {
601            ret = ERR_IO_FAIL;
602            WRITE_LOG(LOG_FATAL, "%s Error uart send to stream", __FUNCTION__);
603        }
604    }
605
606    return ret == RET_SUCCESS;
607}
608
609void HdcUARTBase::NotifyTransfer()
610{
611    WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
612    transfer.Request();
613}
614
615/*
616here we have a HandleOutputPkg vector
617It is used to maintain the data reliability of the link layer
618It consists of the following part
619Log data to send (caller thread)                        --> RequestSendPackage
620Send recorded data (loop sending thread)                --> SendPkgInUARTOutMap
621Process the returned reply data (loop reading thread)   --> ProcessResponsePackage
622Send reply packet (loop reading thread)                 --> ResponseUartTrans
623
624The key scenarios are as follows:
625Package is sent from side A to side B
626Here we call the complete data package
627package is divided into head and data
628The response information is in the header.
629data contains binary data.
630
631case 1: Normal Process
632    package
633A   -->   B
634    ACK
635A   <--   B
636
637case 2: packet is incorrect
638At least one header must be received
639For this the B side needs to have an accept timeout.
640There is no new data within a certain period of time as the end of the packet.
641(This mechanism is not handled in HandleOutputPkg retransmission)
642
643    incorrect
644A   -->   B
645B sends NAK and A resends the packet.
646    NAK
647A   <--   B
648    package resend
649A   -->   B
650
651case 3: packet is complete lost()
652    package(complete lost)
653A   -x->   B
654The A side needs to resend the Package after a certain timeout
655A   -->   B
656Until the B side has a data report (ACK or NAK), or the number of retransmissions reaches the upper
657limit.
658*/
659void HdcUARTBase::RequestSendPackage(uint8_t *data, const size_t length, bool queue)
660{
661    UartHead *head = reinterpret_cast<UartHead *>(data);
662    bool response = head->IsResponsePackage();
663
664    if (queue) {
665        slots.Wait(head->sessionId);
666    }
667
668    std::lock_guard<std::recursive_mutex> lock(mapOutPkgsMutex);
669
670    std::string pkgId = head->ToPkgIdentityString(response);
671    auto it = std::find_if(outPkgs.begin(), outPkgs.end(), HandleOutputPkgKeyFinder(pkgId));
672    if (it == outPkgs.end()) {
673        // update che checksum , both head and data
674        head->UpdateCheckSum();
675        outPkgs.emplace_back(pkgId, head->sessionId, data, length, response,
676                             head->option & PKG_OPTION_ACK);
677        WRITE_LOG(LOG_DEBUG, "UartPackageManager: add pkg %s (pkgs size %zu)",
678                  head->ToDebugString().c_str(), outPkgs.size());
679    } else {
680        WRITE_LOG(LOG_FATAL, "UartPackageManager: add pkg %s fail, %s has already been exist.",
681                  head->ToDebugString().c_str(), pkgId.c_str());
682    }
683    NotifyTransfer();
684}
685
686void HdcUARTBase::ProcessResponsePackage(const UartHead &head)
687{
688    std::lock_guard<std::recursive_mutex> lock(mapOutPkgsMutex);
689    bool ack = head.option & PKG_OPTION_ACK;
690    // response package
691    std::string pkgId = head.ToPkgIdentityString();
692    WRITE_LOG(LOG_ALL, "UartPackageManager: got response pkgId:%s ack:%d.", pkgId.c_str(), ack);
693
694    auto it = std::find_if(outPkgs.begin(), outPkgs.end(), HandleOutputPkgKeyFinder(pkgId));
695    if (it != outPkgs.end()) {
696        if (ack) { // response ACK.
697            slots.Free(it->sessionId);
698            outPkgs.erase(it);
699            WRITE_LOG(LOG_DEBUG, "UartPackageManager: erase pkgId:%s.", pkgId.c_str());
700        } else {                           // response NAK
701            it->pkgStatus = PKG_WAIT_SEND; // Re send the pkg
702            WRITE_LOG(LOG_WARN, "UartPackageManager: resend pkgId:%s.", pkgId.c_str());
703        }
704    } else {
705        WRITE_LOG(LOG_FATAL, "UartPackageManager: hasn't found pkg for pkgId:%s.", pkgId.c_str());
706        for (auto pkg : outPkgs) {
707            WRITE_LOG(LOG_ALL, "UartPackageManager:  pkgId:%s.", pkg.key.c_str());
708        }
709    }
710    NotifyTransfer();
711    return;
712}
713
714void HdcUARTBase::SendPkgInUARTOutMap()
715{
716    std::lock_guard<std::recursive_mutex> lock(mapOutPkgsMutex);
717    if (outPkgs.empty()) {
718        WRITE_LOG(LOG_ALL, "UartPackageManager: No pkgs needs to be sent.");
719        return;
720    }
721    WRITE_LOG(LOG_DEBUG, "UartPackageManager: send pkgs, have:%zu pkgs", outPkgs.size());
722    // we have maybe more than one session
723    // each session has it owner serial port
724    std::unordered_set<uint32_t> hasWaitPkg;
725    auto it = outPkgs.begin();
726    while (it != outPkgs.end()) {
727        if (it->pkgStatus == PKG_WAIT_SEND) {
728            // we found a pkg wait for send
729            // if a response package
730            // response package always send nowait noorder
731            if (!it->response and hasWaitPkg.find(it->sessionId) != hasWaitPkg.end()) {
732                // this is not a response package
733                // and this session is wait response
734                // so we can send nothing
735                // process next
736                it++;
737                continue;
738            }
739            // we will ready to send the package
740            WRITE_LOG(LOG_DEBUG, "UartPackageManager: send pkg %s", it->ToDebugString().c_str());
741            if (!SendUARTRaw(nullptr, it->msgSendBuf.data(), it->msgSendBuf.size())) {
742                WRITE_LOG(LOG_WARN, "SendUARTRaw failed!");
743                break;
744            }
745            if (it->response) {
746                // response pkg dont need wait response again.
747                WRITE_LOG(LOG_DEBUG, "UartPackageManager: erase pkg %s",
748                          it->ToDebugString().c_str());
749                it = outPkgs.erase(it);
750                continue;
751            } else {
752                // normal send package
753                it->pkgStatus = PKG_WAIT_RESPONSE;
754                it->sendTimePoint = steady_clock::now();
755                hasWaitPkg.emplace(it->sessionId);
756                transfer.Sent(); // something is sendout, transfer will timeout for next wait.
757            }
758        } else if (it->pkgStatus == PKG_WAIT_RESPONSE) {
759            // we found a pkg wait for response
760            auto elapsedTime = duration_cast<milliseconds>(steady_clock::now() - it->sendTimePoint);
761            WRITE_LOG(LOG_DEBUG, "UartPackageManager: pkg:%s is wait ACK. elapsedTime %lld",
762                      it->ToDebugString().c_str(), (long long)elapsedTime.count());
763            if (elapsedTime.count() >= WAIT_RESPONSE_TIME_OUT_MS) {
764                // check the response timeout
765                if (it->retryChance > 0) {
766                    // if it send timeout, resend it again.
767                    WRITE_LOG(LOG_WARN, "UartPackageManager: pkg:%s try resend it.",
768                              it->ToDebugString().c_str());
769                    it->pkgStatus = PKG_WAIT_SEND;
770                    it->retryChance--;
771                    NotifyTransfer(); // make transfer reschedule
772                    break;            // dont process anything now.
773                } else {
774                    // the response it timeout and retry counx is 0
775                    // the link maybe not stable
776                    // let's free this session
777                    WRITE_LOG(LOG_WARN, "UartPackageManager: reach max retry ,free the session %u",
778                              it->sessionId);
779                    OnTransferError(GetSession(it->sessionId));
780                    // dont reschedule here
781                    // wait next schedule from this path
782                    // OnTransferError -> FreeSession -> ClearUARTOutMap -> NotifyTransfer
783                    break;
784                }
785            }
786            hasWaitPkg.emplace(it->sessionId);
787        }
788        it++; // next package
789    }
790    WRITE_LOG(LOG_DEBUG, "UartPackageManager: send finish, have %zu pkgs", outPkgs.size());
791}
792
793void HdcUARTBase::ClearUARTOutMap(uint32_t sessionId)
794{
795    WRITE_LOG(LOG_DEBUG, "%s UartPackageManager clean for sessionId %u", __FUNCTION__, sessionId);
796    size_t erased = 0;
797    std::lock_guard<std::recursive_mutex> lock(mapOutPkgsMutex);
798    auto it = outPkgs.begin();
799    while (it != outPkgs.end()) {
800        if (it->sessionId == sessionId) {
801            if (!it->response) {
802                slots.Free(it->sessionId);
803            }
804            it = outPkgs.erase(it);
805            erased++;
806        } else {
807            it++;
808        }
809    }
810    WRITE_LOG(LOG_DEBUG, "%s erased %zu", __FUNCTION__, erased);
811
812    NotifyTransfer(); // tell transfer we maybe have some change
813}
814
815void HdcUARTBase::EnsureAllPkgsSent()
816{
817    WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
818    slots.WaitFree();
819    if (!outPkgs.empty()) {
820        std::this_thread::sleep_for(1000ms);
821    }
822    WRITE_LOG(LOG_DEBUG, "%s done.", __FUNCTION__);
823}
824
825RetErrCode HdcUARTBase::ValidateUartPacket(vector<uint8_t> &data, uint32_t &sessionId,
826                                           uint32_t &packageIndex, size_t &packetSize)
827{
828    constexpr auto maxBufFactor = 1;
829    struct UartHead *head = (struct UartHead *)data.data();
830    WRITE_LOG(LOG_DEBUG, "%s %s", __FUNCTION__, head->ToDebugString().c_str());
831
832    if (memcmp(head->flag, PACKET_FLAG.c_str(), PACKET_FLAG.size()) != 0) {
833        WRITE_LOG(LOG_FATAL, "%s,PACKET_FLAG not correct %x %x", __FUNCTION__, head->flag[0],
834                  head->flag[1]);
835        return ERR_BUF_CHECK;
836    }
837
838    if (!head->ValidateHead()) {
839        WRITE_LOG(LOG_FATAL, "%s head checksum not correct", __FUNCTION__);
840        return ERR_BUF_CHECK;
841    }
842    // after validate , id and fullPackageLength is correct
843    sessionId = head->sessionId;
844    packetSize = head->dataSize + sizeof(UartHead);
845    packageIndex = head->packageIndex;
846
847    if ((head->dataSize + sizeof(UartHead)) > MAX_UART_SIZE_IOBUF * maxBufFactor) {
848        WRITE_LOG(LOG_FATAL, "%s dataSize too larger:%d", __FUNCTION__, head->dataSize);
849        return ERR_BUF_OVERFLOW;
850    }
851
852    if ((head->option & PKG_OPTION_RESET)) {
853        // The Host end program is restarted, but the UART cable is still connected
854        WRITE_LOG(LOG_WARN, "%s host side want restart daemon, restart old sessionId:%u",
855                  __FUNCTION__, head->sessionId);
856        ResetOldSession(head->sessionId);
857        return ERR_IO_SOFT_RESET;
858    }
859
860    if ((head->option & PKG_OPTION_FREE)) {
861        // other side tell us the session need reset
862        // we should free it
863        WRITE_LOG(LOG_WARN, "%s other side tell us the session need free:%u", __FUNCTION__,
864                  head->sessionId);
865        Restartession(GetSession(head->sessionId));
866    }
867
868    // check data
869    if (data.size() >= packetSize) {
870        // if we have full package now ?
871        if (!head->ValidateData()) {
872            WRITE_LOG(LOG_FATAL, "%s data checksum not correct", __FUNCTION__);
873            return ERR_BUF_CHECK;
874        }
875        if (head->IsResponsePackage()) {
876            // response package
877            ProcessResponsePackage(*head);
878        } else {
879            // link layer response for no response package
880            ResponseUartTrans(head->sessionId, head->packageIndex, PKG_OPTION_ACK);
881        }
882    }
883
884    return RET_SUCCESS;
885}
886
887void HdcUARTBase::ResponseUartTrans(uint32_t sessionId, uint32_t packageIndex,
888                                    UartProtocolOption option)
889{
890    UartHead uartHeader(sessionId, option, 0, packageIndex);
891    WRITE_LOG(LOG_DEBUG, "%s option:%u", __FUNCTION__, option);
892    RequestSendPackage(reinterpret_cast<uint8_t *>(&uartHeader), sizeof(UartHead), false);
893}
894
895int HdcUARTBase::SendUARTData(HSession hSession, uint8_t *data, const size_t length)
896{
897    constexpr int maxIOSize = MAX_UART_SIZE_IOBUF;
898    WRITE_LOG(LOG_DEBUG, "SendUARTData hSession:%u, total length:%d", hSession->sessionId, length);
899    const int packageDataMaxSize = maxIOSize - sizeof(UartHead);
900    size_t offset = 0;
901    uint8_t sendDataBuf[MAX_UART_SIZE_IOBUF];
902
903    WRITE_LOG(LOG_ALL, "SendUARTData data length :%d", length);
904
905    do {
906        UartHead *head = (UartHead *)sendDataBuf;
907        if (memset_s(head, sizeof(UartHead), 0, sizeof(UartHead)) != EOK) {
908            return ERR_BUF_RESET;
909        }
910        if (memcpy_s(head->flag, sizeof(head->flag), PACKET_FLAG.c_str(), PACKET_FLAG.size()) !=
911            EOK) {
912            return ERR_BUF_COPY;
913        }
914        head->sessionId = hSession->sessionId;
915        head->packageIndex = ++hSession->hUART->packageIndex;
916
917        int RemainingDataSize = length - offset;
918        if (RemainingDataSize > packageDataMaxSize) {
919            // more than one package max data size
920            head->dataSize = static_cast<uint16_t>(packageDataMaxSize);
921        } else {
922            // less then the max size
923            head->dataSize = static_cast<uint16_t>(RemainingDataSize);
924            // this is the last package . all the data will send after this time
925            head->option = head->option | PKG_OPTION_TAIL;
926        }
927#ifdef UART_FULL_LOG
928        WRITE_LOG(LOG_FULL, "offset %d length %d", offset, length);
929#endif
930        uint8_t *payload = sendDataBuf + sizeof(UartHead);
931        if (EOK !=
932            memcpy_s(payload, packageDataMaxSize, (uint8_t *)data + offset, head->dataSize)) {
933            WRITE_LOG(LOG_FATAL, "memcpy_s failed max %zu , need %zu",
934                      packageDataMaxSize, head->dataSize);
935            return ERR_BUF_COPY;
936        }
937        offset += head->dataSize;
938        int packageFullSize = sizeof(UartHead) + head->dataSize;
939        WRITE_LOG(LOG_ALL, "SendUARTData =============> %s", head->ToDebugString().c_str());
940        RequestSendPackage(sendDataBuf, packageFullSize);
941    } while (offset != length);
942
943    return offset;
944}
945
946void HdcUARTBase::ReadDataFromUARTStream(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
947{
948    HSession hSession = (HSession)stream->data;
949    HdcUARTBase *hUARTBase = (HdcUARTBase *)hSession->classModule;
950    std::lock_guard<std::mutex> lock(hUARTBase->workThreadProcessingData);
951
952    constexpr int bufSize = 1024;
953    char buffer[bufSize] = { 0 };
954    if (nread < 0) {
955        uv_err_name_r(nread, buffer, bufSize);
956    }
957    WRITE_LOG(LOG_DEBUG, "%s sessionId:%u, nread:%zd %s streamSize %zu", __FUNCTION__,
958              hSession->sessionId, nread, buffer,
959              hSession->hUART->streamSize.load());
960    HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance;
961    if (nread <= 0 or nread > signed(hSession->hUART->streamSize)) {
962        WRITE_LOG(LOG_FATAL, "%s nothing need to do ! because no data here", __FUNCTION__);
963        return;
964    }
965    if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread) < 0) {
966        WRITE_LOG(LOG_FATAL, "%s FetchIOBuf failed , free the other side session", __FUNCTION__);
967        // session side said the dont understand this session data
968        // so we also need tell other side to free it session.
969        hUARTBase->ResponseUartTrans(hSession->sessionId, ++hSession->hUART->packageIndex,
970                                     PKG_OPTION_FREE);
971
972        WRITE_LOG(LOG_FATAL, "%s FetchIOBuf failed , free the session", __FUNCTION__);
973        hSessionBase->FreeSession(hSession->sessionId);
974    }
975    hSession->hUART->streamSize -= nread;
976    WRITE_LOG(LOG_DEBUG, "%s sessionId:%u, nread:%d", __FUNCTION__, hSession->sessionId, nread);
977}
978
979bool HdcUARTBase::ReadyForWorkThread(HSession hSession)
980{
981    if (externInterface.UvTcpInit(&hSession->childLoop, &hSession->dataPipe[STREAM_WORK],
982                                  hSession->dataFd[STREAM_WORK])) {
983        WRITE_LOG(LOG_FATAL, "%s init child TCP failed", __FUNCTION__);
984        return false;
985    }
986    hSession->dataPipe[STREAM_WORK].data = hSession;
987    HdcSessionBase *pSession = (HdcSessionBase *)hSession->classInstance;
988    externInterface.SetTcpOptions(&hSession->dataPipe[STREAM_WORK]);
989    if (externInterface.UvRead((uv_stream_t *)&hSession->dataPipe[STREAM_WORK],
990                               pSession->AllocCallback, &HdcUARTBase::ReadDataFromUARTStream)) {
991        WRITE_LOG(LOG_FATAL, "%s child TCP read failed", __FUNCTION__);
992        return false;
993    }
994    WRITE_LOG(LOG_DEBUG, "%s finish", __FUNCTION__);
995    return true;
996}
997
998void HdcUARTBase::Restartession(const HSession session)
999{
1000    if (session != nullptr) {
1001        WRITE_LOG(LOG_FATAL, "%s:%s", __FUNCTION__, session->ToDebugString().c_str());
1002        ClearUARTOutMap(session->sessionId);
1003        sessionBase.FreeSession(session->sessionId);
1004    }
1005}
1006
1007void HdcUARTBase::StopSession(HSession hSession)
1008{
1009    if (hSession != nullptr) {
1010        WRITE_LOG(LOG_WARN, "%s:%s", __FUNCTION__, hSession->ToDebugString().c_str());
1011        ClearUARTOutMap(hSession->sessionId);
1012    } else {
1013        WRITE_LOG(LOG_FATAL, "%s: clean null session", __FUNCTION__);
1014    }
1015}
1016
1017void HdcUARTBase::TransferStateMachine::Wait()
1018{
1019    std::unique_lock<std::mutex> lock(mutex);
1020    WRITE_LOG(LOG_ALL, "%s", __FUNCTION__);
1021    if (timeout) {
1022        auto waitTimeout = std::chrono::duration_cast<std::chrono::milliseconds>(
1023            timeoutPoint - std::chrono::steady_clock::now());
1024        WRITE_LOG(LOG_ALL, "wait timeout %lld", waitTimeout.count());
1025        if (cv.wait_for(lock, waitTimeout, [=] { return requested; }) == false) {
1026            // must wait one timeout
1027            // because sometime maybe not timeout but we got a request first.
1028            timeout = false;
1029            WRITE_LOG(LOG_ALL, "timeout");
1030        }
1031    } else {
1032        cv.wait(lock, [=] { return requested; });
1033    }
1034    requested = false;
1035}
1036
1037HdcUART::HdcUART()
1038{
1039#ifdef _WIN32
1040    Base::ZeroStruct(ovWrite);
1041    ovWrite.hEvent = CreateEvent(NULL, false, false, NULL);
1042    Base::ZeroStruct(ovRead);
1043    ovRead.hEvent = CreateEvent(NULL, false, false, NULL);
1044#endif
1045}
1046
1047HdcUART::~HdcUART()
1048{
1049#ifdef _WIN32
1050    CloseHandle(ovWrite.hEvent);
1051    ovWrite.hEvent = NULL;
1052    CloseHandle(ovRead.hEvent);
1053    ovRead.hEvent = NULL;
1054#endif
1055}
1056} // namespace Hdc
1057#endif // HDC_SUPPORT_UART