• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "daemon_uart.h"
19 
20 #include <thread>
21 #include <fcntl.h>
22 #include <file_ex.h>
23 #include <string_ex.h>
24 
25 #include <sys/file.h>
26 #include <sys/mount.h>
27 #include <sys/select.h>
28 #include <sys/time.h>
29 
30 namespace Hdc {
HdcDaemonUART(HdcDaemon & daemonSessionIn,ExternInterface & externInterface)31 HdcDaemonUART::HdcDaemonUART(HdcDaemon &daemonSessionIn, ExternInterface &externInterface)
32     : HdcUARTBase(daemonSessionIn, externInterface), daemon(daemonSessionIn)
33 {
34     checkSerialPort.data = nullptr;
35 }
36 
Initial(const std::string & devPathIn)37 int HdcDaemonUART::Initial(const std::string &devPathIn)
38 {
39     int ret = 0;
40     devPath = devPathIn;
41     WRITE_LOG(LOG_DEBUG, "HdcDaemonUART init");
42     if (access(devPath.c_str(), F_OK) != 0) {
43         WRITE_LOG(LOG_DEBUG, "uartMod Disable, path is %s and errno is %d.", devPath.c_str(), errno);
44         return -1;
45     }
46 #ifndef HDC_UT
47     std::string consoleActive;
48     if (OHOS::LoadStringFromFile(CONSOLE_ACTIVE_NODE, consoleActive)) {
49         consoleActive = OHOS::TrimStr(consoleActive, '\n');
50         WRITE_LOG(LOG_DEBUG, "consoleActive (%d):%s", consoleActive.length(),
51                   consoleActive.c_str());
52         if (!consoleActive.empty() and devPathIn.find(consoleActive.c_str()) != std::string::npos) {
53             WRITE_LOG(LOG_FATAL,
54                       "kernel use this dev(%s) as console , we can't open it as hdc uart dev",
55                       devPathIn.c_str());
56             return -1;
57         }
58     }
59 #endif
60     constexpr int bufSize = 1024;
61     char buf[bufSize] = { 0 };
62     const uint16_t uartScanInterval = 1500;
63     ret = uv_timer_init(&daemon.loopMain, &checkSerialPort);
64     if (ret != 0) {
65         uv_err_name_r(ret, buf, bufSize);
66         WRITE_LOG(LOG_FATAL, "uv_timer_init failed %s", buf);
67     } else {
68         checkSerialPort.data = this;
69         ret = uv_timer_start(&checkSerialPort, UvWatchTimer, 0, uartScanInterval);
70         if (ret != 0) {
71             uv_err_name_r(ret, buf, bufSize);
72             WRITE_LOG(LOG_FATAL, "uv_timer_start failed %s", buf);
73         } else {
74             return 0;
75         }
76     }
77     return -1;
78 }
79 
PrepareBufForRead()80 int HdcDaemonUART::PrepareBufForRead()
81 {
82     constexpr int bufCoefficient = 1;
83     int readMax = MAX_UART_SIZE_IOBUF * bufCoefficient;
84     dataReadBuf.clear();
85     dataReadBuf.reserve(readMax);
86     return RET_SUCCESS;
87 }
88 
WatcherTimerCallBack()89 void HdcDaemonUART::WatcherTimerCallBack()
90 {
91     // try reanbel the uart device (reopen)
92     if (isAlive) {
93         return;
94     }
95     do {
96         if (uartHandle >= 0) {
97             if (CloseUartDevice() != RET_SUCCESS) {
98                 break;
99             }
100         }
101         if ((OpenUartDevice() != RET_SUCCESS)) {
102             WRITE_LOG(LOG_DEBUG, "OpenUartdevice fail ! ");
103             break;
104         }
105         if ((PrepareBufForRead() != RET_SUCCESS)) {
106             WRITE_LOG(LOG_DEBUG, "PrepareBufForRead fail ! ");
107             break;
108         }
109         // read and write thread need this flag
110         isAlive = true;
111         if ((LoopUARTRead() != RET_SUCCESS)) {
112             WRITE_LOG(LOG_DEBUG, "LoopUARTRead fail ! ");
113             break;
114         }
115         if ((LoopUARTWrite() != RET_SUCCESS)) {
116             WRITE_LOG(LOG_DEBUG, "LoopUARTWrite fail ! ");
117             break;
118         }
119         return;
120     } while (false);
121     WRITE_LOG(LOG_FATAL, "WatcherTimerCallBack found some issue");
122     isAlive = false;
123 }
124 
CloseUartDevice()125 int HdcDaemonUART::CloseUartDevice()
126 {
127     int ret = Base::CloseFd(uartHandle);
128     if (ret < 0) {
129         WRITE_LOG(LOG_FATAL, "CloseUartDevice failed ret: %d", ret);
130     }
131     isAlive = false;
132     return ret;
133 }
134 
OpenUartDevice()135 int HdcDaemonUART::OpenUartDevice()
136 {
137     int ret = ERR_GENERIC;
138     while (true) {
139         if ((uartHandle = open(devPath.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) < 0) {
140             WRITE_LOG(LOG_WARN, "%s: cannot open uartHandle: errno=%d", devPath.c_str(), errno);
141             break;
142         }
143         uv_sleep(UART_IO_WAIT_TIME_100);
144         // cannot open with O_CLOEXEC, must fcntl
145         fcntl(uartHandle, F_SETFD, FD_CLOEXEC);
146         int flag = fcntl(uartHandle, F_GETFL);
147         flag &= ~O_NONBLOCK;
148         fcntl(uartHandle, F_SETFL, flag);
149         WRITE_LOG(LOG_DEBUG, "Set SetSerial ");
150         if (SetSerial(uartHandle, DEFAULT_BAUD_RATE_VALUE, UART_BIT2, 'N', 1) != RET_SUCCESS) {
151             break;
152         }
153         ret = RET_SUCCESS;
154         break;
155     }
156     if (ret != RET_SUCCESS) {
157         WRITE_LOG(LOG_DEBUG, "OpenUartdevice SerialHandle:%d fail.", uartHandle);
158     }
159     return ret;
160 }
161 
ResetOldSession(uint32_t sessionId)162 void HdcDaemonUART::ResetOldSession(uint32_t sessionId)
163 {
164     if (sessionId == 0) {
165         sessionId = currentSessionId;
166     }
167     HSession hSession = daemon.AdminSession(OP_QUERY, sessionId, nullptr);
168     if (hSession == nullptr) {
169         return;
170     }
171     if (hSession->hUART != nullptr) {
172         hSession->hUART->resetIO = true;
173     }
174     // The Host side is restarted, but the USB cable is still connected
175     WRITE_LOG(LOG_WARN, "Hostside softreset to restart daemon, old sessionId:%u", sessionId);
176     OnTransferError(hSession);
177 }
178 
GetSession(const uint32_t sessionId,bool create=false)179 HSession HdcDaemonUART::GetSession(const uint32_t sessionId, bool create = false)
180 {
181     HSession hSession = daemon.AdminSession(OP_QUERY, sessionId, nullptr);
182     if (hSession == nullptr and create) {
183         hSession = PrepareNewSession(sessionId);
184     }
185     return hSession;
186 }
187 
OnTransferError(const HSession session)188 void HdcDaemonUART::OnTransferError(const HSession session)
189 {
190     // review maybe we can do something more ?
191     if (session != nullptr) {
192         WRITE_LOG(LOG_FATAL, "%s %s", __FUNCTION__, session->ToDebugString().c_str());
193         daemon.FreeSession(session->sessionId);
194         ClearUARTOutMap(session->sessionId);
195     }
196 }
197 
OnNewHandshakeOK(const uint32_t sessionId)198 void HdcDaemonUART::OnNewHandshakeOK(const uint32_t sessionId)
199 {
200     currentSessionId = sessionId;
201 }
202 
PrepareNewSession(uint32_t sessionId)203 HSession HdcDaemonUART::PrepareNewSession(uint32_t sessionId)
204 {
205     WRITE_LOG(LOG_FATAL, "%s sessionId:%u", __FUNCTION__, sessionId);
206     HSession hSession = daemon.MallocSession(false, CONN_SERIAL, this, sessionId);
207     if (!hSession) {
208         WRITE_LOG(LOG_FATAL, "new session malloc failed for sessionId:%u", sessionId);
209         return nullptr;
210     }
211     if (currentSessionId != 0) {
212         // reset old session
213         // The Host side is restarted, but the cable is still connected
214         WRITE_LOG(LOG_WARN, "New session coming, restart old sessionId:%u", currentSessionId);
215         daemon.PushAsyncMessage(currentSessionId, ASYNC_FREE_SESSION, nullptr, 0);
216     }
217     externInterface.StartWorkThread(&daemon.loopMain, daemon.SessionWorkThread,
218                                     Base::FinishWorkThread, hSession);
219     auto funcNewSessionUp = [](uv_timer_t *handle) -> void {
220         HSession hSession = reinterpret_cast<HSession>(handle->data);
221         HdcDaemon &daemonSession = *reinterpret_cast<HdcDaemon *>(hSession->classInstance);
222         if (hSession->childLoop.active_handles == 0) {
223             WRITE_LOG(LOG_DEBUG, "No active_handles.");
224             return;
225         }
226         if (!hSession->isDead) {
227             auto ctrl = daemonSession.BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
228             Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
229             WRITE_LOG(LOG_DEBUG, "Main thread uartio migrate finish");
230         }
231         Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
232     };
233     externInterface.TimerUvTask(&daemon.loopMain, hSession, funcNewSessionUp);
234     return hSession;
235 }
236 
237 // review Merge this with Host side
DeamonReadThread()238 void HdcDaemonUART::DeamonReadThread()
239 {
240     HdcUART deamonUart;
241     deamonUart.devUartHandle = uartHandle;
242     dataReadBuf.clear();
243     // after we got the head or something , we will expected some size
244     size_t expectedSize = 0;
245     // use < not <= because if it full , should not read again
246     while (isAlive && dataReadBuf.size() < MAX_READ_BUFFER) {
247         ssize_t bytesRead = ReadUartDev(dataReadBuf, expectedSize, deamonUart);
248         if (bytesRead == 0) {
249             WRITE_LOG(LOG_DEBUG, "%s read %zd, clean the data try read again.", __FUNCTION__,
250                       bytesRead);
251             // drop current cache
252             expectedSize = 0;
253             dataReadBuf.clear();
254             continue;
255         } else if (bytesRead < 0) {
256             WRITE_LOG(LOG_DEBUG, "%s read abnormal, stop uart module.", __FUNCTION__);
257             Stop();
258             break;
259         }
260         WRITE_LOG(LOG_DEBUG, "DeamonReadThread bytesRead:%d, totalReadBytes.size():%d.", bytesRead,
261                   dataReadBuf.size());
262 
263         if (dataReadBuf.size() < sizeof(UartHead)) {
264             continue; // no enough ,read again
265         }
266         expectedSize = PackageProcess(dataReadBuf);
267     }
268     if (isAlive) {
269         WRITE_LOG(LOG_WARN, "totalReadSize is full %zu/%zu, DeamonReadThread exit..",
270                   dataReadBuf.size(), expectedSize);
271     } else {
272         WRITE_LOG(LOG_WARN, "dev is not alive, DeamonReadThread exit..");
273     }
274     // why not free session here
275     isAlive = false;
276     return;
277 }
278 
DeamonWriteThread()279 void HdcDaemonUART::DeamonWriteThread()
280 {
281     while (isAlive) {
282         WRITE_LOG(LOG_DEBUG, "DeamonWriteThread wait sendLock.");
283         transfer.Wait();
284         SendPkgInUARTOutMap();
285     }
286     WRITE_LOG(LOG_WARN, "dev is not alive, DeamonWriteThread exit..");
287     return;
288 }
289 
LoopUARTRead()290 int HdcDaemonUART::LoopUARTRead()
291 {
292     try {
293         std::thread deamonReadThread(std::bind(&HdcDaemonUART::DeamonReadThread, this));
294         deamonReadThread.detach();
295         return 0;
296     } catch (...) {
297         WRITE_LOG(LOG_WARN, "create thread DeamonReadThread failed");
298     }
299     return -1;
300 }
301 
LoopUARTWrite()302 int HdcDaemonUART::LoopUARTWrite()
303 {
304     try {
305         std::thread deamonWriteThread(std::bind(&HdcDaemonUART::DeamonWriteThread, this));
306         deamonWriteThread.detach();
307         return 0;
308     } catch (...) {
309         WRITE_LOG(LOG_WARN, "create thread DeamonWriteThread failed");
310     }
311     return -1;
312 }
313 
IsSendReady(HSession hSession)314 bool HdcDaemonUART::IsSendReady(HSession hSession)
315 {
316     if (isAlive and !hSession->isDead and uartHandle >= 0 and !hSession->hUART->resetIO) {
317         return true;
318     } else {
319         if (!isAlive) {
320             WRITE_LOG(LOG_WARN, "!isAlive");
321         } else if (hSession->isDead) {
322             WRITE_LOG(LOG_WARN, "session isDead");
323         } else if (uartHandle < 0) {
324             WRITE_LOG(LOG_WARN, "uartHandle is not valid");
325         } else if (hSession->hUART->resetIO) {
326             WRITE_LOG(LOG_WARN, "session have resetIO");
327         }
328         return false;
329     }
330 };
331 
~HdcDaemonUART()332 HdcDaemonUART::~HdcDaemonUART()
333 {
334     Stop();
335 }
336 
Stop()337 void HdcDaemonUART::Stop()
338 {
339     WRITE_LOG(LOG_DEBUG, "%s run!", __FUNCTION__);
340     if (!stopped) {
341         stopped = true;
342         std::lock_guard<std::mutex> lock(workThreadProcessingData);
343 
344         // maybe some data response not back to host
345         // like smode need response.
346         ResponseUartTrans(currentSessionId, 0, PKG_OPTION_FREE);
347         EnsureAllPkgsSent();
348         isAlive = false;
349         WRITE_LOG(LOG_DEBUG, "%s free main session", __FUNCTION__);
350         if (checkSerialPort.data != nullptr) {
351             externInterface.TryCloseHandle((uv_handle_t *)&checkSerialPort);
352             checkSerialPort.data = nullptr;
353         }
354         CloseUartDevice();
355         WRITE_LOG(LOG_DEBUG, "%s free main session finish", __FUNCTION__);
356     }
357 }
358 } // namespace Hdc
359 #endif // HDC_SUPPORT_UART
360