/* * Copyright (c) 2023 Fancy Code. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "McuDevice.h" #include "ILog.h" #include constexpr int SLEEP_TIME_MS = 1000; constexpr bool REMOVE_THE_ASK = true; constexpr bool KEEP_THE_ASK = false; /** * @brief Do not use static decoration on this constant pointer, as external test code needs to reference it. * */ const char *MCU_UART_DEVICE_PTR = MCU_UART_DEVICE; McuDevice::McuDevice() { mThreadRuning = false; mUartDevice = nullptr; } McuDevice::~McuDevice() {} const StatusCode McuDevice::Init(void) { UartInfo uartDevice = { MCU_UART_DEVICE_PTR, 1152000, 'N', 8, 1, 'N', }; mUartDevice = CreateUartDevice(uartDevice); if (nullptr == mUartDevice) { LogError("CreateUartDevice failed.\n"); return CreateStatusCode(STATUS_CODE_NOT_OK); } StatusCode code = IUartOpen(mUartDevice); if (IsCodeOK(code) == false) { LogError("IUartOpen failed.\n"); return code; } std::shared_ptr device = std::dynamic_pointer_cast(SharedFromThis()); auto recvThread = [](std::shared_ptr device) { device->DeviceRecvThread(); }; mUartRecvThread = std::thread(recvThread, device); auto mcuAskHandle = [](std::shared_ptr device) { device->McuAskHandleThread(); }; mMcuAskHandleThread = std::thread(mcuAskHandle, device); return CreateStatusCode(STATUS_CODE_OK); } const StatusCode McuDevice::UnInit(void) { mThreadRuning = false; if (mUartRecvThread.joinable()) { mUartRecvThread.join(); } if (mMcuAskHandleThread.joinable()) { mMcuAskHandleThread.join(); } if (nullptr != mUartDevice) { IUartDeviceFree(mUartDevice); } mUartDevice = nullptr; DeleteAllAsk(); return CreateStatusCode(STATUS_CODE_OK); } size_t McuDevice::WriteData(const void *buff, const size_t buffLength, std::shared_ptr &context, const unsigned int &serialNumber) { constexpr int WRITE_ERROR = -1; size_t length = WRITE_ERROR; if (context.get() == nullptr) { /** * @brief A null context pointer indicates that the data is the reply data. * */ mMutex.lock(); length = IUartSend(mUartDevice, buff, buffLength); mMutex.unlock(); return length; } std::shared_ptr>> ctx = std::dynamic_pointer_cast>>(context); if (!ctx) { return WRITE_ERROR; } std::shared_ptr ask = ctx->mData; ask->mSerialNumber = serialNumber; mMutex.lock(); AddMcuAsk(ask); length = IUartSend(mUartDevice, buff, buffLength); mMutex.unlock(); if (ask->NeedReply() == true) { ask->Blocking(); } return length; } void McuDevice::GetIpcMissionReply(const unsigned int &serialNumber, const unsigned char &mission) { std::shared_ptr ask; SearchMcuAsk(serialNumber, ask); if (ask) { std::shared_ptr> realAsk = std::dynamic_pointer_cast>(ask); if (realAsk) { realAsk->mDataReply = static_cast(mission); ask->ReplyFinished(true); } else { ask->ReplyFinished(false); } DeleteMcuAsk(ask); } } void McuDevice::OnlyResultReply(const unsigned int &serialNumber, const ReplyResult &result) { std::shared_ptr ask; SearchMcuAsk(serialNumber, ask); if (ask) { std::shared_ptr> realAsk = std::dynamic_pointer_cast>(ask); if (realAsk) { realAsk->mDataReply = static_cast(result); ask->ReplyFinished(true); } else { ask->ReplyFinished(false); } DeleteMcuAsk(ask); } } void McuDevice::DeviceRecvThread(void) { constexpr int RECV_TIMEOUT_MS = 1000; size_t recvTotalLength = 0; const size_t keyHeadLength = GetKeyHeadLength(); char *keyHeadBuf = (char *)malloc(keyHeadLength); if (nullptr == keyHeadBuf) { LogError("malloc failed, DeviceRecvThread return.\n"); return; } memset(keyHeadBuf, 0, keyHeadLength); mThreadRuning = true; while (mThreadRuning) { ssize_t recvLength = IUartRecv(mUartDevice, keyHeadBuf + recvTotalLength, keyHeadLength - recvTotalLength, RECV_TIMEOUT_MS); LogInfo("mcu recv length = %ld\n", recvLength); if (recvLength <= 0) { // recv failed or recv nothing continue; } recvTotalLength += recvLength; if (keyHeadLength == recvTotalLength) { DeviceRecvData(keyHeadBuf, keyHeadLength); memset(keyHeadBuf, 0, keyHeadLength); recvTotalLength = 0; } } free(keyHeadBuf); } void McuDevice::McuAskHandleThread(void) { while (mThreadRuning) { TraverseCheckAllAsk(); std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_MS)); } } void McuDevice::DeviceRecvData(const char *keyHead, const size_t headLength) { constexpr int RECV_TIMEOUT_MS = 1000; size_t recvTotalLength = 0; size_t dataLength = 0; // const size_t keyHeadLength = GetKeyHeadLength(); const StatusCode code = GetDataLength(keyHead, headLength, dataLength); if (IsCodeOK(code) == false || 0 == dataLength || dataLength <= headLength) { LogError("Recv data error.\n"); return; } char *dataBuf = (char *)malloc(dataLength); if (nullptr == dataBuf) { LogError("malloc failed, DeviceRecvData return.\n"); return; } LogInfo("dataLength = %d\n", dataLength); memset(dataBuf, 0, dataLength); memcpy(dataBuf, keyHead, headLength); while (mThreadRuning) { ssize_t recvLength = IUartRecv(mUartDevice, dataBuf + headLength + recvTotalLength, dataLength - headLength - recvTotalLength, RECV_TIMEOUT_MS); LogInfo("recv data length = %d\n", recvLength); recvTotalLength += recvLength; if (dataLength - headLength == recvTotalLength) { PushMcuData(dataBuf, dataLength); break; } } free(dataBuf); } void McuDevice::AddMcuAsk(std::shared_ptr &ask) { // std::lock_guard locker(mMutex); if (ask->NeedReply() == true) { LogInfo("AddMcuAsk push back one ask serial number = %u.\n", ask->mSerialNumber); mAllAsk.push_back(ask); } } bool McuDevice::SearchMcuAsk(const unsigned int &serialNumber, std::shared_ptr &ask) { // LogInfo("SearchMcuAsk serialNumber = %d\n", serialNumber); std::lock_guard locker(mMutex); for (auto iter = mAllAsk.begin(); iter != mAllAsk.end(); ++iter) { std::shared_ptr listData = *iter; if (!listData) { LogError("Illegal data.\n"); continue; } if (serialNumber == listData->mSerialNumber) { ask = listData; return true; } } LogWarning("Can't find mcu ask recork.\n"); return false; } void McuDevice::DeleteMcuAsk(std::shared_ptr &ask) { std::lock_guard locker(mMutex); auto searchMcuAsk = [&ask](std::shared_ptr &askList) -> bool { if (ask->mSerialNumber == askList->mSerialNumber) { LogInfo("DeleteMcuAsk mSerialNumber = %d\n", askList->mSerialNumber); return REMOVE_THE_ASK; } return KEEP_THE_ASK; }; mAllAsk.remove_if(searchMcuAsk); } void McuDevice::DeleteAllAsk(void) { std::lock_guard locker(mMutex); auto deleteAllAsk = [](std::shared_ptr &askList) -> bool { askList->ReplyFinished(false); return REMOVE_THE_ASK; }; mAllAsk.remove_if(deleteAllAsk); } void McuDevice::TraverseCheckAllAsk(void) { std::lock_guard locker(mMutex); auto ifTimeout = [](std::shared_ptr &ask) -> bool { if (!ask) { return REMOVE_THE_ASK; } if (ask->IfTimeout(SLEEP_TIME_MS) == true) { LogWarning("Mcu ask time out.\n"); ask->ReplyFinished(false); return REMOVE_THE_ASK; } return KEEP_THE_ASK; }; mAllAsk.remove_if(ifTimeout); }