hunting/test/utils/McuProtocol/tool/src/McuProtocolTestTool.cpp
2024-02-10 09:23:51 -08:00

325 lines
15 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 "McuProtocolTestTool.h"
#include "ILog.h"
#include "ModBusCRC16.h"
#include <netinet/in.h>
#include <string.h>
#include <thread>
#include <unistd.h>
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;
constexpr int PIPE_READ_FD_INDEX = 0;
constexpr int PIPE_WRITE_FD_INDEX = 1;
const char *gPipeBuf = "nothing";
constexpr size_t PROTOCOL_DATA_KEY_HEAD_LENGTH = 10;
constexpr size_t PROTOCOL_COMMAND_LENGTH = 6;
constexpr size_t PROTOCOL_CHECK_CODE_LENGTH = sizeof(short);
constexpr size_t PROTOCOL_SERIAL_NUMBER_LENGTH = sizeof(unsigned int);
unsigned char ASK_IPC_MISSION[] = {0xFA, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x0C, 0x71, 0x88};
unsigned char REPLY_IPC_MISSION[] = {0xFA, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x0D, 0x01, 0xAA, 0x89};
unsigned char ASK_CUT_OFF_POWER_SUPPLY[] = {0xFA, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x81, 0x02, 0x00, 0x0C, 0x81, 0x88};
unsigned char ASK_FEED_WATCH_DOG[] = {0xFA, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x81, 0x03, 0x00, 0x0C, 0xD0, 0x48};
unsigned char ASK_SET_FEEDING_CYCLE[] = {
0xFA, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x81, 0x04, 0x00, 0x0F, 0x01, 0x01, 0x01, 0xA7, 0x9A};
unsigned char REPLY_SET_FEEDING_CYCLE[] = {
0xFA, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x0D, 0x01, 0x52, 0x26};
McuProtocolTestTool::McuProtocolTestTool()
{
mThreadRuning = false;
mPipeFdMockSelectInit = false;
mPipeFdMockSelect[PIPE_READ_FD_INDEX] = -1;
mPipeFdMockSelect[PIPE_WRITE_FD_INDEX] = -1;
mProtocolHandle.push_back(std::bind(&McuProtocolTestTool::IpcMissionProtocolHandle, this, _1, _2, _3, _4));
mProtocolHandle.push_back(std::bind(&McuProtocolTestTool::CutOffPowerSupplyProtocolHandle, this, _1, _2, _3, _4));
mProtocolHandle.push_back(std::bind(&McuProtocolTestTool::FeedWatchDogProtocolHandle, this, _1, _2, _3, _4));
mProtocolHandle.push_back(std::bind(&McuProtocolTestTool::FeedingCycleProtocolHandle, this, _1, _2, _3, _4));
}
void McuProtocolTestTool::Init(std::shared_ptr<LinuxTest> &mock, const UartInfo &uart)
{
if (pipe(mPipeFdMockSelect) == 0) {
mPipeFdMockSelectInit = true;
}
else {
LogWarning("pipe failed, mPipeFdMockSelect willn,t work.\n");
}
int uartFd = GetDeviceMockFd(uart);
static size_t WRITE_COUNT = -1;
auto api_write = [=, &mock](int fd, const void *buf, size_t count) {
McuProtocolTestTool::PrintHexadecimalData(buf, count, WRITE_PRINT);
CheckSerialNumber(buf, count);
ChecCRC16Code(buf, count);
for (auto iter = mProtocolHandle.begin(); iter != mProtocolHandle.end(); ++iter) {
if ((*iter)(mock, uartFd, buf, count) == PROTOCOL_HANDLED) {
return;
}
}
};
EXPECT_CALL(*mock.get(), fx_write(uartFd, _, _))
.WillRepeatedly(
DoAll(SaveArg<2>(&WRITE_COUNT), WithArgs<0, 1, 2>(Invoke(api_write)), ReturnPointee(&WRITE_COUNT)));
}
void McuProtocolTestTool::UnInit(void)
{
if (mLockThread.joinable()) {
mLockThread.join();
}
if (mUnLockThread.joinable()) {
mUnLockThread.join();
}
mSerialNumberList.clear();
if (mPipeFdMockSelectInit) {
close(mPipeFdMockSelect[PIPE_READ_FD_INDEX]);
close(mPipeFdMockSelect[PIPE_WRITE_FD_INDEX]);
mPipeFdMockSelect[PIPE_READ_FD_INDEX] = -1;
mPipeFdMockSelect[PIPE_WRITE_FD_INDEX] = -1;
}
mPipeFdMockSelectInit = false;
}
void McuProtocolTestTool::CheckSerialNumber(const void *buf, const size_t &count)
{
unsigned int serialNumber = 0;
if (count > PROTOCOL_COMMAND_LENGTH + PROTOCOL_CHECK_CODE_LENGTH) {
memcpy(&serialNumber, (unsigned char *)buf + 2, 4);
for (auto iter = mSerialNumberList.begin(); iter != mSerialNumberList.end(); ++iter) {
EXPECT_NE(*iter, serialNumber);
}
mSerialNumberList.push_back(serialNumber);
}
}
void McuProtocolTestTool::ChecCRC16Code(const void *buf, const size_t &count)
{
short code = calculate_check_sum((unsigned char *)buf, count - PROTOCOL_CHECK_CODE_LENGTH);
EXPECT_EQ(memcmp((unsigned char *)buf + count - PROTOCOL_CHECK_CODE_LENGTH, &code, 2), 0);
}
void McuProtocolTestTool::ResetCheckCode(const void *buf, const size_t &count)
{
short checkCode = calculate_check_sum((unsigned char *)buf, count - PROTOCOL_CHECK_CODE_LENGTH);
// checkCode = htons(checkCode);
memcpy((unsigned char *)buf + count - PROTOCOL_CHECK_CODE_LENGTH, &checkCode, PROTOCOL_CHECK_CODE_LENGTH);
}
void McuProtocolTestTool::ReplySelectSucceed(std::shared_ptr<LinuxTest> &mock, const int &uartFd)
{
auto selectReadable =
[=, &mock](int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
FD_ZERO(readfds);
FD_SET(uartFd, readfds);
};
auto selectTimeOut =
[=, &mock](int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
if (false == mPipeFdMockSelectInit) {
long long timeMs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
std::this_thread::sleep_for(std::chrono::milliseconds(timeMs));
}
else {
constexpr int READ_BUF_LENGTH = 256;
constexpr int READ_FAILD = -1;
char buf[READ_BUF_LENGTH] = {0};
int selectResult = -1;
fd_set fdsRead;
FD_ZERO(&fdsRead);
FD_SET(mPipeFdMockSelect[PIPE_READ_FD_INDEX], &fdsRead);
selectResult = select(mPipeFdMockSelect[PIPE_READ_FD_INDEX] + 1, &fdsRead, NULL, NULL, timeout);
if (selectResult) {
// Do nothing here.
ssize_t length = read(mPipeFdMockSelect[PIPE_READ_FD_INDEX], buf, READ_BUF_LENGTH);
if (READ_FAILD == length) {
LogError("mPipeFdMockSelect failed.\n");
return;
}
if ((size_t)length != strlen(gPipeBuf)) {
LogWarning("Something wrong happened.\n");
}
}
}
};
EXPECT_CALL(*mock.get(), fx_select(uartFd + 1, _, _, _, _))
.WillOnce(DoAll(WithArgs<0, 1, 2, 3, 4>(Invoke(selectReadable)), Return(1)))
.WillOnce(DoAll(WithArgs<0, 1, 2, 3, 4>(Invoke(selectReadable)), Return(1)))
.WillRepeatedly(DoAll(WithArgs<0, 1, 2, 3, 4>(Invoke(selectTimeOut)), Return(MOCK_SELECT_TIME_OUT)));
PipeSelectTimeoutForProtocolHandleImmediately();
}
bool McuProtocolTestTool::IpcMissionProtocolHandle(std::shared_ptr<LinuxTest> &mock, const int &uartFd, const void *buf,
size_t count)
{
if (sizeof(ASK_IPC_MISSION) == count &&
memcmp(ASK_IPC_MISSION + PROTOCOL_COMMAND_LENGTH, (unsigned char *)buf + PROTOCOL_COMMAND_LENGTH, 2) == 0) {
LogInfo("Set REPLY_IPC_MISSION\n");
short askCheckCode = calculate_check_sum(ASK_IPC_MISSION, sizeof(ASK_IPC_MISSION) - PROTOCOL_CHECK_CODE_LENGTH);
askCheckCode = htons(askCheckCode);
EXPECT_EQ(memcmp((unsigned char *)ASK_IPC_MISSION + count - PROTOCOL_CHECK_CODE_LENGTH, &askCheckCode, 2), 0);
auto handle = [=, &mock](McuProtocolTestTool *testTool) {
testTool->IpcMissionProtocolInit(mock, uartFd, buf, count);
};
if (mLockThread.joinable()) {
mLockThread.join();
}
mLockThread = std::thread(handle, this);
return PROTOCOL_HANDLED;
}
return PROTOCOL_NOT_HANDLED;
}
void McuProtocolTestTool::IpcMissionProtocolInit(std::shared_ptr<LinuxTest> &mock, const int &uartFd, const void *buf,
size_t count)
{
LockProtocolHandle();
memcpy(REPLY_IPC_MISSION + 2, (unsigned char *)buf + 2, PROTOCOL_SERIAL_NUMBER_LENGTH);
ResetCheckCode(REPLY_IPC_MISSION, sizeof(REPLY_IPC_MISSION));
ReplySelectSucceed(mock, uartFd);
constexpr int LEFT_DATA_LENGTH = sizeof(REPLY_IPC_MISSION) - PROTOCOL_DATA_KEY_HEAD_LENGTH;
auto apiReadKeyHead = [=](int fd, void *buf, size_t count) {
memcpy(buf, REPLY_IPC_MISSION, PROTOCOL_DATA_KEY_HEAD_LENGTH);
McuProtocolTestTool::PrintHexadecimalData(buf, PROTOCOL_DATA_KEY_HEAD_LENGTH, READ_PRINT);
};
auto apiReadLeftData = [=](int fd, void *buf, size_t count) {
memcpy(buf, REPLY_IPC_MISSION + PROTOCOL_DATA_KEY_HEAD_LENGTH, LEFT_DATA_LENGTH);
McuProtocolTestTool::PrintHexadecimalData(buf, LEFT_DATA_LENGTH, READ_PRINT);
UnlockProtocolHandle();
};
EXPECT_CALL(*mock.get(), fx_read(uartFd, _, _))
.WillOnce(DoAll(WithArgs<0, 1, 2>(Invoke(apiReadKeyHead)), Return(PROTOCOL_DATA_KEY_HEAD_LENGTH)))
.WillOnce(DoAll(WithArgs<0, 1, 2>(Invoke(apiReadLeftData)), Return(LEFT_DATA_LENGTH)))
.WillRepeatedly(DoAll(Return(UART_DEVICE_READ_NOTHING)));
}
bool McuProtocolTestTool::CutOffPowerSupplyProtocolHandle(std::shared_ptr<LinuxTest> &mock, const int &uartFd,
const void *buf, size_t count)
{
if (sizeof(ASK_CUT_OFF_POWER_SUPPLY) == count &&
memcmp(ASK_CUT_OFF_POWER_SUPPLY + PROTOCOL_COMMAND_LENGTH, (unsigned char *)buf + PROTOCOL_COMMAND_LENGTH, 2) ==
0) {
LogInfo("Set ASK_CUT_OFF_POWER_SUPPLY\n");
short askCheckCode = calculate_check_sum(ASK_CUT_OFF_POWER_SUPPLY,
sizeof(ASK_CUT_OFF_POWER_SUPPLY) - PROTOCOL_CHECK_CODE_LENGTH);
askCheckCode = htons(askCheckCode);
EXPECT_EQ(
memcmp((unsigned char *)ASK_CUT_OFF_POWER_SUPPLY + count - PROTOCOL_CHECK_CODE_LENGTH, &askCheckCode, 2),
0);
// IpcMissionProtocolInit(mock, uartFd);
return PROTOCOL_HANDLED;
}
return PROTOCOL_NOT_HANDLED;
}
bool McuProtocolTestTool::FeedWatchDogProtocolHandle(std::shared_ptr<LinuxTest> &mock, const int &uartFd,
const void *buf, size_t count)
{
if (sizeof(ASK_FEED_WATCH_DOG) == count &&
memcmp(ASK_FEED_WATCH_DOG + PROTOCOL_COMMAND_LENGTH, (unsigned char *)buf + PROTOCOL_COMMAND_LENGTH, 2) == 0) {
LogInfo("Set ASK_FEED_WATCH_DOG\n");
short askCheckCode =
calculate_check_sum(ASK_FEED_WATCH_DOG, sizeof(ASK_FEED_WATCH_DOG) - PROTOCOL_CHECK_CODE_LENGTH);
askCheckCode = htons(askCheckCode);
EXPECT_EQ(memcmp((unsigned char *)ASK_FEED_WATCH_DOG + count - PROTOCOL_CHECK_CODE_LENGTH, &askCheckCode, 2),
0);
// IpcMissionProtocolInit(mock, uartFd);
return PROTOCOL_HANDLED;
}
return PROTOCOL_NOT_HANDLED;
}
bool McuProtocolTestTool::FeedingCycleProtocolHandle(std::shared_ptr<LinuxTest> &mock, const int &uartFd,
const void *buf, size_t count)
{
if (sizeof(ASK_SET_FEEDING_CYCLE) == count &&
memcmp(ASK_SET_FEEDING_CYCLE + PROTOCOL_COMMAND_LENGTH, (unsigned char *)buf + PROTOCOL_COMMAND_LENGTH, 2) ==
0) {
short replyCheckCode =
calculate_check_sum(REPLY_SET_FEEDING_CYCLE, sizeof(REPLY_SET_FEEDING_CYCLE) - PROTOCOL_CHECK_CODE_LENGTH);
replyCheckCode = htons(replyCheckCode);
LogInfo("Set ASK_SET_FEEDING_CYCLE, reply data check code = 0x%x\n", replyCheckCode);
short askCheckCode =
calculate_check_sum(ASK_SET_FEEDING_CYCLE, sizeof(ASK_SET_FEEDING_CYCLE) - PROTOCOL_CHECK_CODE_LENGTH);
askCheckCode = htons(askCheckCode);
EXPECT_EQ(memcmp((unsigned char *)ASK_SET_FEEDING_CYCLE + count - PROTOCOL_CHECK_CODE_LENGTH, &askCheckCode, 2),
0);
auto handle = [=, &mock](McuProtocolTestTool *testTool) {
testTool->FeedingCycleProtocolInit(mock, uartFd, buf, count);
};
if (mLockThread.joinable()) {
mLockThread.join();
}
mLockThread = std::thread(handle, this);
// FeedingCycleProtocolInit(mock, uartFd);
return PROTOCOL_HANDLED;
}
return PROTOCOL_NOT_HANDLED;
}
void McuProtocolTestTool::FeedingCycleProtocolInit(std::shared_ptr<LinuxTest> &mock, const int &uartFd, const void *buf,
size_t count)
{
LockProtocolHandle();
memcpy(REPLY_SET_FEEDING_CYCLE + 2, (unsigned char *)buf + 2, PROTOCOL_SERIAL_NUMBER_LENGTH);
ResetCheckCode(REPLY_SET_FEEDING_CYCLE, sizeof(REPLY_SET_FEEDING_CYCLE));
ReplySelectSucceed(mock, uartFd);
constexpr int LEFT_DATA_LENGTH = sizeof(REPLY_SET_FEEDING_CYCLE) - PROTOCOL_DATA_KEY_HEAD_LENGTH;
auto apiReadKeyHead = [=](int fd, void *buf, size_t count) {
memcpy(buf, REPLY_SET_FEEDING_CYCLE, PROTOCOL_DATA_KEY_HEAD_LENGTH);
McuProtocolTestTool::PrintHexadecimalData(buf, PROTOCOL_DATA_KEY_HEAD_LENGTH, READ_PRINT);
};
auto apiReadLeftData = [=](int fd, void *buf, size_t count) {
memcpy(buf, REPLY_SET_FEEDING_CYCLE + PROTOCOL_DATA_KEY_HEAD_LENGTH, LEFT_DATA_LENGTH);
McuProtocolTestTool::PrintHexadecimalData(buf, LEFT_DATA_LENGTH, READ_PRINT);
UnlockProtocolHandle();
};
EXPECT_CALL(*mock.get(), fx_read(uartFd, _, _))
.WillOnce(DoAll(WithArgs<0, 1, 2>(Invoke(apiReadKeyHead)), Return(PROTOCOL_DATA_KEY_HEAD_LENGTH)))
.WillOnce(DoAll(WithArgs<0, 1, 2>(Invoke(apiReadLeftData)), Return(LEFT_DATA_LENGTH)))
.WillRepeatedly(DoAll(Return(UART_DEVICE_READ_NOTHING)));
}
void McuProtocolTestTool::UnlockProtocolHandle(void)
{
auto unlockThread = [=](McuProtocolTestTool *testTool) { testTool->UnlockThread(); };
if (mUnLockThread.joinable()) {
mUnLockThread.join();
}
mUnLockThread = std::thread(unlockThread, this);
}
void McuProtocolTestTool::LockProtocolHandle(void)
{
//
mMutex.lock();
}
void McuProtocolTestTool::UnlockThread(void)
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
mMutex.unlock();
}
void McuProtocolTestTool::PipeSelectTimeoutForProtocolHandleImmediately(void)
{
constexpr int WRITE_FAILD = -1;
if (true == mPipeFdMockSelectInit) {
ssize_t length = write(mPipeFdMockSelect[PIPE_WRITE_FD_INDEX], gPipeBuf, strlen(gPipeBuf));
if (WRITE_FAILD == length) {
LogError("mPipeFdMockSelect failed.\n");
return;
}
if ((size_t)length != strlen(gPipeBuf)) {
LogWarning("Something wrong happened.\n");
}
}
}
void McuProtocolTestTool::PrintHexadecimalData(const void *buf, const size_t &bufLength, const int event)
{
if (WRITE_PRINT == event) {
printf("TEST write buf = { 0x%02X", *(unsigned char *)buf);
}
if (READ_PRINT == event) {
printf("TEST read buf = { 0x%02X", *(unsigned char *)buf);
}
for (size_t i = 1; i < bufLength; i++) {
printf(", 0x%02X", *((unsigned char *)buf + i));
}
printf(" }\n");
}