/*================================================================================================== * Project : S32K3_miniEvb * Platform : CORTEXM * Peripheral : S32K3XX * Dependencies : none * * Autosar Version : 4.7.0 * Autosar Revision : ASR_REL_4_7_REV_0000 * Autosar Conf.Variant : * SW Version : 0.1.0 * Build Version : * * Copyright 2026 - 20xx HuaXu * * HuaXu Confidential. This software is owned or controlled by HuaXu and may only be * used strictly in accordance with the applicable license terms. By expressly * accepting such terms or by downloading, installing, activating and/or otherwise * using the software, you are agreeing that you have read, and that you agree to * comply with and are bound by, such license terms. If you do not agree to be * bound by the applicable license terms, then you may not retain, install, * activate or otherwise use the software. ==================================================================================================*/ /*================================================================================================== * File version history: * 0.1.0 initial version ==================================================================================================*/ /** * @file spi_protocol.hpp * @version 0.1.0 * @brief SPI Protocol v2.0 — SOC/MCU 通信组包/解包 * * @addtogroup SPI * @{ */ #ifndef SPI_PROTOCOL_HPP #define SPI_PROTOCOL_HPP #ifdef __cplusplus extern "C"{ #endif /*================================================================================================== INCLUDE FILES ==================================================================================================*/ #include /*================================================================================================== CONSTANTS ==================================================================================================*/ /* 帧固定字段 */ #define SPI_PROTO_SOF 0xAAu #define SPI_PROTO_EOF 0x55u #define SPI_PROTO_VERSION 0x01u /* 帧长配置(4 选 1) */ #define SPI_PROTO_FRAME_64 64u #define SPI_PROTO_FRAME_128 128u #define SPI_PROTO_FRAME_256 256u #define SPI_PROTO_FRAME_512 512u #define SPI_PROTO_FRAME_1024 1024u /* 默认帧长 */ #define SPI_PROTO_FRAME_SIZE SPI_PROTO_FRAME_128 /* HEAD 长度 = Version(1) + FrameType(1) + Seq(2) + Timestamp(4) + PacketCount(1) + TotalLen(2) */ #define SPI_PROTO_HEAD_LEN 11u /* 帧开销 = SOF(1) + HEAD(11) + CRC16(2) + EOF(1) */ #define SPI_PROTO_OVERHEAD 15u /* 最大 Payload 字节数 */ #define SPI_PROTO_MAX_PAYLOAD (SPI_PROTO_FRAME_SIZE - SPI_PROTO_OVERHEAD) /* 最大 TLV 数量 */ #define SPI_PROTO_MAX_TLV_COUNT 16u /* TLV 头部长度 = ServiceID(1) + MethodID(1) + Length(2) */ #define SPI_PROTO_TLV_HEAD_LEN 4u /* ——— FrameType ——— */ typedef enum { SPI_PROTO_FRAME_DATA = 0x00u, /* MCU→SOC 常规上报 */ SPI_PROTO_FRAME_CTRL = 0x01u, /* SOC→MCU 控制/配置 */ SPI_PROTO_FRAME_ACK = 0x02u, /* 通用确认 */ SPI_PROTO_FRAME_NACK = 0x03u, /* 错误应答 */ SPI_PROTO_FRAME_HEARTBEAT = 0x04u /* 心跳 */ } SpiProtocol_FrameType; /* ——— ServiceID ——— */ #define SPI_PROTO_SID_SYSTEM 0x01u #define SPI_PROTO_SID_AC 0x02u #define SPI_PROTO_SID_KEY 0x03u #define SPI_PROTO_SID_VEHICLE 0x04u #define SPI_PROTO_SID_CAN 0x05u #define SPI_PROTO_SID_UPDATE 0x06u #define SPI_PROTO_SID_CLUSTER 0x07u #define SPI_PROTO_SID_LOG 0x08u #define SPI_PROTO_SID_TEST 0x09u #define SPI_PROTO_SID_DIAG 0x0Au #define SPI_PROTO_SID_PASS 0x0Bu #define SPI_PROTO_SID_AUDIO 0x0Cu #define SPI_PROTO_SID_AVM 0x0Du #define SPI_PROTO_SID_BSD 0x0Eu #define SPI_PROTO_SID_DMS 0x0Fu #define SPI_PROTO_SID_ADAS 0x10u #define SPI_PROTO_SID_THEME 0x11u #define SPI_PROTO_SID_POWERMANAGER 0x12u #define SPI_PROTO_SID_RVC 0x13u #define SPI_PROTO_SID_ERROR 0xFEu /* NACK 错误信息 */ /* ——— NACK 错误码 ——— */ #define SPI_PROTO_ERR_NONE 0x00u #define SPI_PROTO_ERR_CRC 0x01u #define SPI_PROTO_ERR_VERSION 0x02u #define SPI_PROTO_ERR_SOF 0x03u #define SPI_PROTO_ERR_EOF 0x04u #define SPI_PROTO_ERR_TOTALLEN 0x05u #define SPI_PROTO_ERR_TLV_PARSE 0x06u #define SPI_PROTO_ERR_PKTCOUNT 0x07u #define SPI_PROTO_ERR_FRAMETYPE 0x08u #define SPI_PROTO_ERR_PADDING 0x09u #define SPI_PROTO_ERR_TRUNCATED 0x0Au /* ——— 解包返回码 ——— */ #define SPI_PROTO_OK 0 #define SPI_PROTO_ERR_PARAM (-1) #define SPI_PROTO_ERR_SIZE (-2) #define SPI_PROTO_ERR_SOF_MISMATCH (-3) #define SPI_PROTO_ERR_EOF_MISMATCH (-4) #define SPI_PROTO_ERR_CRC_MISMATCH (-5) #define SPI_PROTO_ERR_VERSION_MISMATCH (-6) #define SPI_PROTO_ERR_TOTALLEN_OVF (-7) #define SPI_PROTO_ERR_PKTCOUNT_OVF (-8) #define SPI_PROTO_ERR_TLV_TRUNC (-9) #define SPI_PROTO_ERR_PADDING_NZ (-10) #define SPI_PROTO_ERR_FRAME_SHORT (-11) /*================================================================================================== TYPEDEFS ==================================================================================================*/ /** * @brief TLV 子包描述 * @note value 指针由调用方管理,组包时指向待发送数据,解包时指向 frame 内数据 */ typedef struct { uint8_t service_id; /**< 业务大类 */ uint8_t method_id; /**< 业务子类 */ uint16_t length; /**< Value 字节数(不含 T+L) */ const uint8_t *value; /**< Value 数据指针 */ } SpiProtocol_TlvType; /** * @brief 解包输出结果 */ typedef struct { SpiProtocol_FrameType frame_type; /**< 帧类型 */ uint16_t seq; /**< 帧序号 */ uint32_t timestamp; /**< 时间戳 (ms) */ uint8_t tlv_count; /**< 实际 TLV 数量 */ SpiProtocol_TlvType tlvs[SPI_PROTO_MAX_TLV_COUNT]; /**< TLV 列表 */ uint8_t nack_error_code; /**< NACK 帧时有效 */ } SpiProtocol_RxResultType; /*================================================================================================== GLOBAL FUNCTION PROTOTYPES ==================================================================================================*/ /** * @brief 计算 CRC16(HEAD + Payload 范围) * @param data 数据起始指针(指向 HEAD 首字节 Version) * @param len 数据长度 * @return CRC16 值 */ uint16_t SpiProtocol_CalcCrc16(const uint8_t *data, uint16_t len); /** * @brief 组包:将 TLV 列表打包为完整帧 * @param frame 输出帧缓冲区(调用方分配,大小 ≥ SPI_PROTO_FRAME_SIZE) * @param frame_size 帧长配置(128/256/512/1024) * @param frame_type 帧类型 * @param seq 帧序号 * @param timestamp 时间戳 (ms) * @param tlvs TLV 数组 * @param tlv_count TLV 数量 * @return >=0: 实际帧字节数(= frame_size); <0: 错误码 */ int32_t SpiProtocol_Pack(uint8_t *frame, uint16_t frame_size, SpiProtocol_FrameType frame_type, uint16_t seq, uint32_t timestamp, const SpiProtocol_TlvType *tlvs, uint8_t tlv_count); /** * @brief 解包:解析接收帧,输出 TLV 列表 * @param frame 接收帧缓冲区 * @param frame_len 接收数据长度 * @param frame_size 预期帧长配置(128/256/512/1024) * @param result 输出解析结果 * @return >=0: 成功(返回 TLV 数量); <0: 错误码 */ int32_t SpiProtocol_Unpack(const uint8_t *frame, uint16_t frame_len, uint16_t frame_size, SpiProtocol_RxResultType *result); /** * @brief 构造 ACK 帧(确认指定 seq 的帧) * @param frame 输出帧缓冲区 * @param frame_size 帧长配置 * @param ack_seq 被确认帧的序号 * @return >=0: 实际帧字节数; <0: 错误码 */ int32_t SpiProtocol_PackAck(uint8_t *frame, uint16_t frame_size, uint16_t ack_seq); /** * @brief 构造 NACK 帧 * @param frame 输出帧缓冲区 * @param frame_size 帧长配置 * @param ack_seq 被否定应答帧的序号 * @param error_code 错误码(见 SPI_PROTO_ERR_xxx) * @return >=0: 实际帧字节数; <0: 错误码 */ int32_t SpiProtocol_PackNack(uint8_t *frame, uint16_t frame_size, uint16_t ack_seq, uint8_t error_code); /** * @brief 构造心跳帧 * @param frame 输出帧缓冲区 * @param frame_size 帧长配置 * @param seq 帧序号 * @return >=0: 实际帧字节数; <0: 错误码 */ int32_t SpiProtocol_PackHeartbeat(uint8_t *frame, uint16_t frame_size, uint16_t seq); #ifdef __cplusplus } #endif #endif /* SPI_PROTOCOL_HPP */ /** @} */