Files
SOMEIP/source/soa_server/spi_protocol.hpp

244 lines
9.3 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*==================================================================================================
* 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 <stdint.h>
/*==================================================================================================
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 计算 CRC16HEAD + 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 */
/** @} */