325 lines
15 KiB
C++
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");
|
|
} |