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 SendToPollFd(int fd, const uint8_t *buf, const int len); 145 virtual int UvTcpInit(uv_loop_t *, uv_tcp_t *, int); 146 virtual int UvRead(uv_stream_t *, uv_alloc_cb, uv_read_cb); 147 virtual int StartWorkThread(uv_loop_t *loop, uv_work_cb pFuncWorkThread, 148 uv_after_work_cb pFuncAfterThread, void *pThreadData); 149 virtual void TryCloseHandle(const uv_handle_t *handle, uv_close_cb closeCallBack = nullptr); 150 virtual bool TimerUvTask(uv_loop_t *loop, void *data, uv_timer_cb cb); 151 virtual bool UvTimerStart(uv_timer_t *handle, uv_timer_cb cb, uint64_t timeout, 152 uint64_t repeat); 153 using DelayCB = std::function<void(const uint8_t, string &, const void *)>; 154 virtual bool DelayDo(uv_loop_t *loop, const int delayMs, const uint8_t flag, string msg, 155 void *data, DelayCB cb); 156 virtual ~ExternInterface() = default; 157 }; 158 class HdcSessionBase; 159 class HdcUARTBase { 160 public: 161 static ExternInterface defaultInterface; 162 HdcUARTBase(HdcSessionBase &, ExternInterface & = defaultInterface); 163 virtual ~HdcUARTBase(); 164 bool ReadyForWorkThread(HSession hSession); 165 int SendUARTData(HSession hSession, uint8_t *data, const size_t length); 166 // call from session side 167 // we need know when we need clear the pending send data 168 virtual void StopSession(HSession hSession); 169 170 protected: 171 static constexpr uint32_t DEFAULT_BAUD_RATE_VALUE = 1500000; 172 173 bool stopped = false; // stop only can be call one times 174 175 // something is processing on working thread 176 // Mainly used to reply a data back before stop. 177 std::mutex workThreadProcessingData; 178 179 // review how about make a HUART in daemon side and put the devhandle in it ? 180 int uartHandle = -1; 181 virtual bool SendUARTRaw(HSession hSession, uint8_t *data, const size_t length); SendUartSoftReset(HSession hUART,uint32_t sessionId)182 virtual void SendUartSoftReset(HSession hUART, uint32_t sessionId) {}; 183 virtual RetErrCode ValidateUartPacket(vector<uint8_t> &data, uint32_t &sessionId, 184 uint32_t &packageIndex, size_t &fullPackageLength); 185 virtual void NotifyTransfer(); ResetOldSession(uint32_t sessionId)186 virtual void ResetOldSession(uint32_t sessionId) 187 { 188 return; 189 } 190 virtual void Restartession(const HSession session); 191 192 #ifndef _WIN32 193 int SetSerial(int fd, int nSpeed, int nBits, char nEvent, int nStop); 194 #endif // _WIN32 195 virtual bool UartSendToHdcStream(HSession hSession, uint8_t *data, size_t size); 196 static void ReadDataFromUARTStream(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); 197 bool uartOpened; 198 199 static constexpr size_t MAX_READ_BUFFER = MAX_UART_SIZE_IOBUF * 10; 200 static constexpr int READ_GIVE_UP_TIME_OUT_TIME_MS = 500; // 500ms 201 virtual int UartToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize); 202 int GetUartSpeed(int speed); 203 int GetUartBits(int bits); 204 virtual void ResponseUartTrans(uint32_t sessionId, uint32_t packageIndex, 205 UartProtocolOption option); 206 207 virtual size_t PackageProcess(vector<uint8_t> &data, HSession hSession = nullptr); 208 virtual RetErrCode DispatchToWorkThread(HSession hSession, uint8_t *readBuf, int readBytes); 209 210 virtual void OnTransferError(const HSession session) = 0; 211 virtual HSession GetSession(const uint32_t sessionId, bool create = false) = 0; 212 213 /* 214 read data from uart devices 215 Args: 216 readBuf data will append to readBuf 217 expectedSize function will not return until expected size read 218 219 Return: 220 ssize_t > 0 how many bytes read after this function called 221 == 0 nothing read , timeout happened(expectedSize > 0) 222 < 0 means devices error 223 */ 224 225 // we have some oswait in huart(bind to each session/uart device) 226 virtual ssize_t ReadUartDev(std::vector<uint8_t> &readBuf, size_t expectedSize, HdcUART &uart); 227 228 virtual ssize_t WriteUartDev(uint8_t *data, const size_t length, HdcUART &uart); 229 230 ExternInterface &externInterface; 231 232 virtual void RequestSendPackage(uint8_t *data, const size_t length, bool queue = true); 233 virtual void ProcessResponsePackage(const UartHead &head); 234 virtual void SendPkgInUARTOutMap(); 235 virtual void ClearUARTOutMap(uint32_t sessionId); 236 virtual void EnsureAllPkgsSent(); 237 static constexpr int WAIT_RESPONSE_TIME_OUT_MS = 1000; // 1000ms 238 static constexpr int OneMoreMs = 1; 239 240 class TransferStateMachine { 241 public: Request()242 void Request() 243 { 244 std::unique_lock<std::mutex> lock(mutex); 245 requested = true; 246 cv.notify_one(); 247 } 248 Sent()249 void Sent() 250 { 251 std::unique_lock<std::mutex> lock(mutex); 252 timeout = true; 253 // wait_for will timeout in 999ms in linux platform, so we add one more 254 timeoutPoint = std::chrono::steady_clock::now() + 255 std::chrono::milliseconds(WAIT_RESPONSE_TIME_OUT_MS + OneMoreMs); 256 cv.notify_one(); 257 } 258 259 void Wait(); 260 261 private: 262 std::mutex mutex; 263 std::condition_variable cv; 264 bool requested = false; // some one request send something 265 std::chrono::steady_clock::time_point timeoutPoint; 266 bool timeout = false; // some data is sendout and next wait need wait response 267 } transfer; 268 269 private: 270 HdcSessionBase &sessionBase; 271 272 enum PkgStatus { 273 PKG_WAIT_SEND, 274 PKG_WAIT_RESPONSE, 275 }; 276 struct HandleOutputPkg { 277 std::string key; 278 uint32_t sessionId = 0; // like group , sometimes we will delete by this filter 279 bool response; // PKG for response 280 bool ack; // UartResponseCode for this package 281 uint8_t pkgStatus; 282 vector<uint8_t> msgSendBuf; 283 size_t retryChance = 4; // how many time need retry 284 std::chrono::time_point<std::chrono::steady_clock> sendTimePoint; 285 // reivew if we need direct process UartHead ? 286 HandleOutputPkg(std::string keyIn, uint32_t sessionIdIn, uint8_t *data, size_t length, 287 bool responseIn = false, bool ackIn = false) keyHandleOutputPkg288 : key(keyIn), 289 sessionId(sessionIdIn), 290 response(responseIn), 291 ack(ackIn), 292 pkgStatus(PKG_WAIT_SEND), 293 msgSendBuf(data, data + length) 294 { 295 } ToDebugStringHandleOutputPkg296 std::string ToDebugString() 297 { 298 std::string debug; 299 debug.append(key); 300 debug.append(" pkgStatus:"); 301 debug.append(std::to_string(pkgStatus)); 302 if (pkgStatus == PKG_WAIT_RESPONSE) { 303 debug.append(" sent:"); 304 auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>( 305 std::chrono::steady_clock::now() - sendTimePoint); 306 debug.append(std::to_string(elapsedTime.count())); 307 debug.append(" ms"); 308 debug.append(" retry Chance:"); 309 debug.append(std::to_string(retryChance)); 310 } 311 if (response) { 312 debug.append(" response:"); 313 if (ack) { 314 debug.append(" ACK"); 315 } else { 316 debug.append(" NAK"); 317 } 318 } 319 return debug; 320 } 321 }; 322 323 class TransferSlot { 324 public: Wait(uint32_t sessionId)325 void Wait(uint32_t sessionId) 326 { 327 std::unique_lock<std::mutex> lock(mutex); 328 cv.wait(lock, [=] { return hasWaitPkg.find(sessionId) == hasWaitPkg.end(); }); 329 hasWaitPkg.emplace(sessionId); 330 } 331 Free(uint32_t sessionId)332 void Free(uint32_t sessionId) 333 { 334 std::unique_lock<std::mutex> lock(mutex); 335 hasWaitPkg.erase(sessionId); 336 cv.notify_one(); 337 } 338 339 // call when exit WaitFree()340 void WaitFree() 341 { 342 std::unique_lock<std::mutex> lock(mutex); 343 cv.wait_for(lock, std::chrono::milliseconds(WAIT_RESPONSE_TIME_OUT_MS), 344 [=] { return hasWaitPkg.size() == 0; }); 345 } 346 347 private: 348 std::mutex mutex; 349 std::condition_variable cv; 350 std::unordered_set<uint32_t> hasWaitPkg; 351 } slots; 352 353 vector<HandleOutputPkg> outPkgs; // Pkg label, HOutPkg 354 std::recursive_mutex mapOutPkgsMutex; 355 struct HandleOutputPkgKeyFinder { 356 const std::string &key; HandleOutputPkgKeyFinderHandleOutputPkgKeyFinder357 HandleOutputPkgKeyFinder(const std::string &keyIn) : key(keyIn) {} operatorHandleOutputPkgKeyFinder358 bool operator()(const HandleOutputPkg &other) 359 { 360 return key == other.key; 361 } 362 }; 363 }; 364 } // namespace Hdc 365 #endif 366