/* * 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 #include #include #include 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 &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 &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 &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 &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 &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 &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 &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 &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"); }