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 #ifndef HDC_UART_H 16 #define HDC_UART_H 17 #include "common.h" 18 19 #include <chrono> 20 #include <numeric> 21 #include <sstream> 22 #include <unordered_set> 23 24 #ifndef _WIN32 25 #include <termios.h> // struct termios 26 #endif // _WIN32 27 28 namespace Hdc { 29 #define USE_UART_CHECKSUM // all the data and head will have a checksum 30 #undef HDC_UART_TIMER_LOG // will have a lot of log from timer 31 32 enum UartProtocolOption { 33 PKG_OPTION_TAIL = 1, // makr is the last packget, can be send to session. 34 PKG_OPTION_RESET = 2, // host request reset session in daemon 35 PKG_OPTION_ACK = 4, // response the pkg is received 36 PKG_OPTION_NAK = 8, // request resend pkg again 37 PKG_OPTION_FREE = 16, // request free this session, some unable recovery error happened 38 }; 39 40 static_assert(MAX_UART_SIZE_IOBUF != 0); 41 42 #pragma pack(push) 43 #pragma pack(1) 44 struct UartHead { 45 UartHead(const UartHead &) = delete; 46 UartHead &operator=(const UartHead &) = delete; 47 UartHead(UartHead &&) = default; 48 49 uint8_t flag[2]; // magic word 50 uint16_t option; // UartProtocolOption 51 uint32_t sessionId; // the package owner (COM dev owner) 52 uint32_t dataSize; // data size not include head 53 uint32_t packageIndex; // package index in this session 54 uint32_t dataCheckSum = 0; // data checksum 55 uint32_t headCheckSum = 0; // head checksum 56 std::string ToPkgIdentityString(bool responsePackage = false) const 57 { 58 std::ostringstream oss; 59 if (responsePackage) { 60 oss << "R-"; 61 } 62 oss << "Id:" << sessionId; 63 oss << "pkgIdx:" << packageIndex; 64 return oss.str(); 65 }; ToDebugStringUartHead66 std::string ToDebugString() const 67 { 68 std::ostringstream oss; 69 oss << "UartHead ["; 70 oss << " flag:" << std::hex << unsigned(flag[0]) << " " << unsigned(flag[1]) << std::dec; 71 oss << " option:" << unsigned(option); 72 oss << " sessionId:" << sessionId; 73 oss << " dataSize:" << dataSize; 74 oss << " packageIndex:" << packageIndex; 75 if (dataSize != 0) { 76 oss << " dataCheckSum:" << std::hex << dataCheckSum; 77 } 78 oss << " headCheckSum:" << std::hex << headCheckSum; 79 oss << std::dec; 80 oss << "]"; 81 return oss.str(); 82 }; 83 UartHead(uint32_t sessionIdIn = 0, uint8_t optionIn = 0, uint32_t dataSizeIn = 0, 84 uint32_t packageIndexIn = 0) 85 : flag {PACKET_FLAG[0], PACKET_FLAG[1]}, 86 option(optionIn), 87 sessionId(sessionIdIn), 88 dataSize(dataSizeIn), 89 packageIndex(packageIndexIn) 90 { 91 } 92 bool operator==(const UartHead &r) const 93 { 94 return flag[0] == r.flag[0] and flag[1] == r.flag[1] and option == r.option and 95 dataSize == r.dataSize and packageIndex == r.packageIndex; 96 } IsResponsePackageUartHead97 bool IsResponsePackage() const 98 { 99 return (option & PKG_OPTION_ACK) or (option & PKG_OPTION_NAK); 100 } UpdateCheckSumUartHead101 void UpdateCheckSum() 102 { 103 #ifdef USE_UART_CHECKSUM 104 if (dataSize != 0) { 105 const uint8_t *data = reinterpret_cast<const uint8_t *>(this) + sizeof(UartHead); 106 dataCheckSum = std::accumulate(data, data + dataSize, 0u); 107 } 108 const uint8_t *head = reinterpret_cast<const uint8_t *>(this); 109 size_t headCheckSumLen = sizeof(UartHead) - sizeof(headCheckSum); 110 headCheckSum = std::accumulate(head, head + headCheckSumLen, 0u); 111 #endif 112 } ValidateHeadUartHead113 bool ValidateHead() const 114 { 115 #ifdef USE_UART_CHECKSUM 116 const uint8_t *head = reinterpret_cast<const uint8_t *>(this); 117 size_t headCheckSumLen = sizeof(UartHead) - sizeof(headCheckSum); 118 return (headCheckSum == std::accumulate(head, head + headCheckSumLen, 0u)); 119 #else 120 return true; 121 #endif 122 } ValidateDataUartHead123 bool ValidateData() const 124 { 125 #ifdef USE_UART_CHECKSUM 126 const uint8_t *data = reinterpret_cast<const uint8_t *>(this) + sizeof(UartHead); 127 if (dataSize == 0) { 128 return true; 129 } else { 130 return (dataCheckSum == std::accumulate(data, data + dataSize, 0u)); 131 } 132 #else 133 return true; 134 #endif 135 } 136 }; 137 #pragma pack(pop) 138 139 // we need virtual interface for UT the free function 140 class ExternInterface { 141 public: 142 virtual void SetTcpOptions(uv_tcp_t *tcpHandle); 143 virtual int SendToStream(uv_stream_t *handleStream, const uint8_t *buf, const int bufLen); 144 virtual int UvTcpInit(uv_loop_t *, uv_tcp_t *, int); 145 virtual int UvRead(uv_stream_t *, uv_alloc_cb, uv_read_cb); 146 virtual int StartWorkThread(uv_loop_t *loop, uv_work_cb pFuncWorkThread, 147 uv_after_work_cb pFuncAfterThread, void *pThreadData); 148 virtual void TryCloseHandle(const uv_handle_t *handle, uv_close_cb closeCallBack = nullptr); 149 virtual bool TimerUvTask(uv_loop_t *loop, void *data, uv_timer_cb cb); 150 virtual bool UvTimerStart(uv_timer_t *handle, uv_timer_cb cb, uint64_t timeout, 151 uint64_t repeat); 152 using DelayCB = std::function<void(const uint8_t, string &, const void *)>; 153 virtual bool DelayDo(uv_loop_t *loop, const int delayMs, const uint8_t flag, string msg, 154 void *data, DelayCB cb); 155 virtual ~ExternInterface() = default; 156 }; 157 class HdcSessionBase; 158 class HdcUARTBase { 159 public: 160 static ExternInterface defaultInterface; 161 HdcUARTBase(HdcSessionBase &, ExternInterface & = defaultInterface); 162 virtual ~HdcUARTBase(); 163 bool ReadyForWorkThread(HSession hSession); 164 int SendUARTData(HSession hSession, uint8_t *data, const size_t length); 165 // call from session side 166 // we need know when we need clear the pending send data 167 virtual void StopSession(HSession hSession); 168 169 protected: 170 static constexpr uint32_t DEFAULT_BAUD_RATE_VALUE = 1500000; 171 172 bool stopped = false; // stop only can be call one times 173 174 // something is processing on working thread 175 // Mainly used to reply a data back before stop. 176 std::mutex workThreadProcessingData; 177 178 // review how about make a HUART in daemon side and put the devhandle in it ? 179 int uartHandle = -1; 180 virtual bool SendUARTRaw(HSession hSession, uint8_t *data, const size_t length); SendUartSoftReset(HSession hUART,uint32_t sessionId)181 virtual void SendUartSoftReset(HSession hUART, uint32_t sessionId) {}; 182 virtual RetErrCode ValidateUartPacket(vector<uint8_t> &data, uint32_t &sessionId, 183 uint32_t &packageIndex, size_t &fullPackageLength); 184 virtual void NotifyTransfer(); ResetOldSession(uint32_t sessionId)185 virtual void ResetOldSession(uint32_t sessionId) 186 { 187 return; 188 } 189 virtual void Restartession(const HSession session); 190 191 #ifndef _WIN32 192 int SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop); 193 #endif // _WIN32 194 virtual bool UartSendToHdcStream(HSession hSession, uint8_t *data, size_t size); 195 static void ReadDataFromUARTStream(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); 196 bool uartOpened; 197 198 static constexpr size_t MAX_READ_BUFFER = MAX_UART_SIZE_IOBUF * 10; 199 static constexpr int ReadGiveUpTimeOutTimeMs = 500; // 500ms 200 virtual int UartToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize); 201 int GetUartSpeed(int speed); 202 int GetUartBits(int bits); 203 virtual void ResponseUartTrans(uint32_t sessionId, uint32_t packageIndex, 204 UartProtocolOption option); 205 206 virtual size_t PackageProcess(vector<uint8_t> &data, HSession hSession = nullptr); 207 virtual RetErrCode DispatchToWorkThread(HSession hSession, uint8_t *readBuf, int readBytes); 208 209 virtual void OnTransferError(const HSession session) = 0; 210 virtual HSession GetSession(const uint32_t sessionId, bool create = false) = 0; 211 212 /* 213 read data from uart devices 214 Args: 215 readBuf data will append to readBuf 216 expectedSize function will not return until expected size read 217 218 Return: 219 ssize_t > 0 how many bytes read after this function called 220 == 0 nothing read , timeout happened(expectedSize > 0) 221 < 0 means devices error 222 */ 223 224 // we have some oswait in huart(bind to each session/uart device) 225 virtual ssize_t ReadUartDev(std::vector<uint8_t> &readBuf, size_t expectedSize, HdcUART &uart); 226 227 virtual ssize_t WriteUartDev(uint8_t *data, const size_t length, HdcUART &uart); 228 229 ExternInterface &externInterface; 230 231 virtual void RequestSendPackage(uint8_t *data, const size_t length, bool queue = true); 232 virtual void ProcessResponsePackage(const UartHead &head); 233 virtual void SendPkgInUARTOutMap(); 234 virtual void ClearUARTOutMap(uint32_t sessionId); 235 virtual void EnsureAllPkgsSent(); 236 static constexpr int WaitResponseTimeOutMs = 1000; // 1000ms 237 static constexpr int OneMoreMs = 1; 238 239 class TransferStateMachine { 240 public: Request()241 void Request() 242 { 243 std::unique_lock<std::mutex> lock(mutex); 244 requested = true; 245 cv.notify_one(); 246 } 247 Sent()248 void Sent() 249 { 250 std::unique_lock<std::mutex> lock(mutex); 251 timeout = true; 252 // wait_for will timeout in 999ms in linux platform, so we add one more 253 timeoutPoint = std::chrono::steady_clock::now() + 254 std::chrono::milliseconds(WaitResponseTimeOutMs + OneMoreMs); 255 cv.notify_one(); 256 } 257 258 void Wait(); 259 260 private: 261 std::mutex mutex; 262 std::condition_variable cv; 263 bool requested = false; // some one request send something 264 std::chrono::steady_clock::time_point timeoutPoint; 265 bool timeout = false; // some data is sendout and next wait need wait response 266 } transfer; 267 268 private: 269 HdcSessionBase &sessionBase; 270 271 enum PkgStatus { 272 PKG_WAIT_SEND, 273 PKG_WAIT_RESPONSE, 274 }; 275 struct HandleOutputPkg { 276 std::string key; 277 uint32_t sessionId = 0; // like group , sometimes we will delete by this filter 278 bool response; // PKG for response 279 bool ack; // UartResponseCode for this package 280 uint8_t pkgStatus; 281 vector<uint8_t> msgSendBuf; 282 size_t retryChance = 4; // how many time need retry 283 std::chrono::time_point<std::chrono::steady_clock> sendTimePoint; 284 // reivew if we need direct process UartHead ? 285 HandleOutputPkg(std::string keyIn, uint32_t sessionIdIn, uint8_t *data, size_t length, 286 bool responseIn = false, bool ackIn = false) keyHandleOutputPkg287 : key(keyIn), 288 sessionId(sessionIdIn), 289 response(responseIn), 290 ack(ackIn), 291 pkgStatus(PKG_WAIT_SEND), 292 msgSendBuf(data, data + length) 293 { 294 } ToDebugStringHandleOutputPkg295 std::string ToDebugString() 296 { 297 std::string debug; 298 debug.append(key); 299 debug.append(" pkgStatus:"); 300 debug.append(std::to_string(pkgStatus)); 301 if (pkgStatus == PKG_WAIT_RESPONSE) { 302 debug.append(" sent:"); 303 auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>( 304 std::chrono::steady_clock::now() - sendTimePoint); 305 debug.append(std::to_string(elapsedTime.count())); 306 debug.append(" ms"); 307 debug.append(" retry Chance:"); 308 debug.append(std::to_string(retryChance)); 309 } 310 if (response) { 311 debug.append(" response:"); 312 if (ack) { 313 debug.append(" ACK"); 314 } else { 315 debug.append(" NAK"); 316 } 317 } 318 return debug; 319 } 320 }; 321 322 class TransferSlot { 323 public: Wait(uint32_t sessionId)324 void Wait(uint32_t sessionId) 325 { 326 std::unique_lock<std::mutex> lock(mutex); 327 cv.wait(lock, [=] { return hasWaitPkg.find(sessionId) == hasWaitPkg.end(); }); 328 hasWaitPkg.emplace(sessionId); 329 } 330 Free(uint32_t sessionId)331 void Free(uint32_t sessionId) 332 { 333 std::unique_lock<std::mutex> lock(mutex); 334 hasWaitPkg.erase(sessionId); 335 cv.notify_one(); 336 } 337 338 // call when exit WaitFree()339 void WaitFree() 340 { 341 std::unique_lock<std::mutex> lock(mutex); 342 cv.wait_for(lock, std::chrono::milliseconds(WaitResponseTimeOutMs), 343 [=] { return hasWaitPkg.size() == 0; }); 344 } 345 346 private: 347 std::mutex mutex; 348 std::condition_variable cv; 349 std::unordered_set<uint32_t> hasWaitPkg; 350 } slots; 351 352 vector<HandleOutputPkg> outPkgs; // Pkg label, HOutPkg 353 std::recursive_mutex mapOutPkgsMutex; 354 struct HandleOutputPkgKeyFinder { 355 const std::string &key; HandleOutputPkgKeyFinderHandleOutputPkgKeyFinder356 HandleOutputPkgKeyFinder(const std::string &keyIn) : key(keyIn) {} operatorHandleOutputPkgKeyFinder357 bool operator()(const HandleOutputPkg &other) 358 { 359 return key == other.key; 360 } 361 }; 362 }; 363 } // namespace Hdc 364 #endif 365