/* * 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. */ #ifndef PROTOCOL_HANDLE_H #define PROTOCOL_HANDLE_H #include "ILog.h" #include "StatusCode.h" #include #include #include #include constexpr char ORDER_BIG_ENDIAN = 0x01; constexpr char ORDER_LITTLE_ENDIAN = 0x02; constexpr size_t KEY_HEAD_LENGTH = sizeof(short) + sizeof(unsigned int) + sizeof(short) + sizeof(short); constexpr size_t CHECK_CODE_LENGTH = sizeof(short); constexpr unsigned int SERIAL_NUMBER_NEED_TO_MAKE_A_LOCAL_ONE = 0; #pragma pack(1) typedef struct protocol_packet { short mHead; unsigned int mSerialNumber; short mCommand; short mLength; // char *mData; short mCheckCode; } ProtocolPacket; #pragma pack() constexpr unsigned short PROTOCOL_HEAD = 0xFAC1; enum PROTOCOL_COMMAND { ASK_IPC_MISSION = 0x8101, REPLY_IPC_MISSION = 0x0101, ASK_CUT_OFF_PWOER_SUPPLY = 0x8102, ASK_FEED_WATCH_DOG = 0x8103, ASK_SET_FEEDING_CYCLE = 0x8104, REPLY_SET_FEEDING_CYCLE = 0x0104, ASK_SET_DATE_TIME = 0x8107, REPLY_SET_DATE_TIME = 0x0107, ASK_SET_PIR_SENSITIVITY = 0x8108, REPLY_SET_PIR_SENSITIVITY = 0x0108, ASK_CONTORL_INFRARED_LIGHT = 0x810A, REPLY_CONTORL_INFRARED_LIGHT = 0x010A, ASK_GET_PHOTOSENSITIVITY = 0x810B, REPLY_GET_PHOTOSENSITIVITY = 0x010B, /** * @brief The protocol starting from here is a request sent from the other end. * */ REPLY_OTHER_SIDE_ASK_SEND_IPC_MISSION = 0xC101, OTHER_SIDE_ASK_SEND_IPC_MISSION = 0x4101, PROTOCOL_COMMAND_END }; constexpr unsigned char ZERO_MEANS_SHUTDOWN_WATCH_DOG = 0x00; #pragma pack(1) typedef struct watch_dog_param { watch_dog_param(const unsigned char &hour, const unsigned char &min, const unsigned char &second) : mHour(hour), mMin(min), mSecond(second) { } const unsigned char mHour; const unsigned char mMin; const unsigned char mSecond; } WatchDogParam; typedef struct set_date_time { set_date_time(const unsigned short &year, const unsigned char &mon, const unsigned char &day, const unsigned char &hour, const unsigned char &min, const unsigned char &second) : mYear(year), mMon(mon), mDay(day), mHour(hour), mMin(min), mSecond(second) { } const unsigned short mYear; const unsigned char mMon; const unsigned char mDay; const unsigned char mHour; const unsigned char mMin; const unsigned char mSecond; } SetDateTime; #pragma pack() class VProtocolParam { public: VProtocolParam(const PROTOCOL_COMMAND &command) : mCommand(command) { mSerialNumber = SERIAL_NUMBER_NEED_TO_MAKE_A_LOCAL_ONE; } virtual ~VProtocolParam() = default; const PROTOCOL_COMMAND mCommand; unsigned int mSerialNumber; }; template class ProtocolParam : public VProtocolParam { public: ProtocolParam(const PROTOCOL_COMMAND &command, T &value) : VProtocolParam(command), mData(value) {} virtual ~ProtocolParam() = default; public: /** * @brief * Protocol data. */ T mData; }; using MakePacketFunc = std::function &)>; using AnalyzePacketFunc = std::function; /** * @brief Protocol processing classes need to focus on data size issues, and ProtocolHandle defaults to handling large * end data. */ class ProtocolHandle { public: ProtocolHandle(const std::shared_ptr ¶m); ProtocolHandle(const void *data, const size_t &length); virtual ~ProtocolHandle(); void *GetProtocolDataBuff(void) { return mProtocolData; } size_t GetProtocolDataLength(void) { return mProtocolDataLength; } unsigned int GetSerialNumber(void) { return mProtocolSerialNumber; } /** * @brief These functions assemble scattered data into continuous memory protocol packets and complete the sending * of protocol packets. */ private: ProtocolPacket CreatePocketWithSerialNumber(void); void MallocPacketDataBuff(const void *data, const size_t dataLength, const short &command); void MakeProtocolPacket(const std::shared_ptr ¶m); void MakeNoUserDataPacket(const std::shared_ptr ¶m); void MakeAskIpcMissionPacket(const std::shared_ptr ¶m); void MakeAskCutOffPowerSupplyPacket(const std::shared_ptr ¶m); void MakeAskFeedWatchDogPacket(const std::shared_ptr ¶m); void MakeAskSetFeedingCyclePacket(const std::shared_ptr ¶m); void MakeAskSetDateTimePacket(const std::shared_ptr ¶m); void MakeAskSetPirSensitivityPacket(const std::shared_ptr ¶m); void MakeAskControlInfraredLightPacket(const std::shared_ptr ¶m); void MakeAskGetPhotosensitivityPacket(const std::shared_ptr ¶m); void MakeReplyOtherSideSendIpcMissionPacket(const std::shared_ptr ¶m); template void MakeProtocolData(const std::shared_ptr ¶m) { constexpr int PARAM_DATA_LENGTH = sizeof(T); std::shared_ptr> SetParam = std::dynamic_pointer_cast>(param); if (!SetParam) { LogError("Invalid param.\n"); return; } MallocPacketDataBuff(&(SetParam->mData), PARAM_DATA_LENGTH, param->mCommand); } private: /** * @brief These function implementations parse the received frame by frame continuous data into the data required by * the application, completing the protocol unpacking. */ void AnalyzeProtocolPacket(void); unsigned char ReplyOneBytePacketResult(const ProtocolPacket &packet); void AnalyzeReplyResultPacket(const ProtocolPacket &packet); void AnalyzeReplyIpcMissionPacket(const ProtocolPacket &packet); void AnalyzeOtherSideSendIpcMissionPacket(const ProtocolPacket &packet); private: virtual void BigEndianConversion(ProtocolPacket &packet) {} virtual short BigEndianConversion(const short &number) { return number; } virtual void HostByteOrderConversion(ProtocolPacket &packet) {} virtual bool CheckoutTheCheckCode(const ProtocolPacket &packet); protected: std::shared_ptr mParam; std::map mMakePacketFunc; std::map mAnalyzePacketFunc; unsigned char *mProtocolData; size_t mProtocolDataLength; /** * @brief Single protocol package serial number. * */ unsigned int mProtocolSerialNumber; /** * @brief The global protocol packet serial number is used to bind the data content of the one question one answer * protocol. * */ static unsigned int mSerialNumber; static std::mutex mMutex; public: static void Init(void); static void UnInit(void); static std::shared_ptr CreateProtocolData(const std::shared_ptr ¶m); static void ProtocolAnalysis(const void *data, const size_t &length); static size_t GetKeyHeadLength(void); static StatusCode GetDataLength(const void *keyHead, const size_t &headLength, size_t &dataLength); static char GetByteOrder(void); static void PrintHexadecimalData(const void *buf, const size_t &bufLength, const char *log = nullptr); }; #endif