269 lines
8.9 KiB
C++
269 lines
8.9 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;
|
|
}
|
|
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);
|
|
}
|
|
size_t McuDevice::WriteData(const void *buff, const size_t buffLength, std::shared_ptr<VProtocolContext> &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<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 (ask->NeedReply() == true) {
|
|
ask->Blocking();
|
|
}
|
|
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);
|
|
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<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);
|
|
} |