hunting/middleware/McuManager/src/McuDevice.cpp
2024-05-11 11:27:29 +08:00

282 lines
9.1 KiB
C++

/*
* 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 <string.h>
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;
}
mThreadRuning = true;
std::shared_ptr<McuDevice> device = std::dynamic_pointer_cast<McuDevice>(SharedFromThis());
auto recvThread = [](std::shared_ptr<McuDevice> device) {
device->DeviceRecvThread();
};
mUartRecvThread = std::thread(recvThread, device);
auto mcuAskHandle = [](std::shared_ptr<McuDevice> 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);
}
ssize_t McuDevice::WriteData(const void *buff, const size_t buffLength, std::shared_ptr<VProtocolContext> &context,
const unsigned int &serialNumber)
{
constexpr size_t 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<ProtocolContext<std::shared_ptr<VMcuAsk>>> ctx =
std::dynamic_pointer_cast<ProtocolContext<std::shared_ptr<VMcuAsk>>>(context);
if (!ctx) {
return WRITE_ERROR;
}
std::shared_ptr<VMcuAsk> ask = ctx->mData;
ask->mSerialNumber = serialNumber;
mMutex.lock();
AddMcuAsk(ask);
length = IUartSend(mUartDevice, buff, buffLength);
mMutex.unlock();
if (WRITE_ERROR == length) {
LogError("Uart send failed, something wrong happened.\n");
ask->ReplyFinished(false);
DeleteMcuAsk(ask);
goto END;
}
if (ask->NeedReply() == true) {
ask->Blocking();
}
END:
return length;
}
void McuDevice::GetIpcMissionReply(const unsigned int &serialNumber, const unsigned char &mission)
{
std::shared_ptr<VMcuAsk> ask;
SearchMcuAsk(serialNumber, ask);
if (ask) {
std::shared_ptr<McuAsk<IpcMission>> realAsk = std::dynamic_pointer_cast<McuAsk<IpcMission>>(ask);
if (realAsk) {
realAsk->mDataReply = static_cast<IpcMission>(mission);
ask->ReplyFinished(true);
}
else {
ask->ReplyFinished(false);
}
DeleteMcuAsk(ask);
}
}
void McuDevice::OnlyResultReply(const unsigned int &serialNumber, const ReplyResult &result)
{
std::shared_ptr<VMcuAsk> ask;
SearchMcuAsk(serialNumber, ask);
if (ask) {
std::shared_ptr<McuAsk<ASK_RESULT>> realAsk = std::dynamic_pointer_cast<McuAsk<ASK_RESULT>>(ask);
if (realAsk) {
realAsk->mDataReply = static_cast<ASK_RESULT>(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);
while (mThreadRuning) {
ssize_t recvLength =
IUartRecv(mUartDevice, keyHeadBuf + recvTotalLength, keyHeadLength - recvTotalLength, RECV_TIMEOUT_MS);
if (recvLength <= 0) { // recv failed or recv nothing
continue;
}
LogInfo("mcu recv length = %ld\n", recvLength);
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<VMcuAsk> &ask)
{
// std::lock_guard<std::mutex> 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<VMcuAsk> &ask)
{
// LogInfo("SearchMcuAsk serialNumber = %d\n", serialNumber);
std::lock_guard<std::mutex> locker(mMutex);
for (auto iter = mAllAsk.begin(); iter != mAllAsk.end(); ++iter) {
std::shared_ptr<VMcuAsk> 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<VMcuAsk> &ask)
{
std::lock_guard<std::mutex> locker(mMutex);
auto searchMcuAsk = [&ask](std::shared_ptr<VMcuAsk> &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<std::mutex> locker(mMutex);
auto deleteAllAsk = [](std::shared_ptr<VMcuAsk> &askList) -> bool {
askList->ReplyFinished(false);
return REMOVE_THE_ASK;
};
mAllAsk.remove_if(deleteAllAsk);
}
void McuDevice::TraverseCheckAllAsk(void)
{
std::lock_guard<std::mutex> locker(mMutex);
auto ifTimeout = [](std::shared_ptr<VMcuAsk> &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);
}