Files
SOMEIP/source/soa_server/spi_protocol.cpp

429 lines
17 KiB
C++
Raw Permalink Normal View History

/*==================================================================================================
* Project : S32K3_miniEvb
* Platform : CORTEXM
* Peripheral : S32K3XX
* Dependencies : spi_protocol.h
*
* 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.c
* @version 0.1.0
* @brief SPI Protocol v2.0 /
*
* (Big Endian):
* ~
* SOF Ver FType Seq Timestamp PktCntTotalLen TLVs... CRC16 EOF 0x00...
* 1B 1B 1B 2B 4B 1B 2B variable 2B 1B pad
* ~
*
* CRC
* (HEAD + TLVs, SOF/EOF/Padding)
*
* @addtogroup SPI
* @{
*/
/*==================================================================================================
INCLUDE FILES
==================================================================================================*/
#include "spi_protocol.hpp"
#include <string.h>
/*==================================================================================================
LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
static void SpiProtocol_WriteBe16(uint8_t *buf, uint16_t val);
static void SpiProtocol_WriteBe32(uint8_t *buf, uint32_t val);
static uint16_t SpiProtocol_ReadBe16(const uint8_t *buf);
static uint32_t SpiProtocol_ReadBe32(const uint8_t *buf);
/*==================================================================================================
LOCAL FUNCTION DEFINITIONS
==================================================================================================*/
/**
* @brief 16
*/
static void SpiProtocol_WriteBe16(uint8_t *buf, uint16_t val)
{
buf[0] = (uint8_t)((val >> 8) & 0xFFu);
buf[1] = (uint8_t)(val & 0xFFu);
}
/**
* @brief 32
*/
static void SpiProtocol_WriteBe32(uint8_t *buf, uint32_t val)
{
buf[0] = (uint8_t)((val >> 24) & 0xFFu);
buf[1] = (uint8_t)((val >> 16) & 0xFFu);
buf[2] = (uint8_t)((val >> 8) & 0xFFu);
buf[3] = (uint8_t)(val & 0xFFu);
}
/**
* @brief 16
*/
static uint16_t SpiProtocol_ReadBe16(const uint8_t *buf)
{
return (uint16_t)(((uint16_t)buf[0] << 8) | (uint16_t)buf[1]);
}
/**
* @brief 32
*/
static uint32_t SpiProtocol_ReadBe32(const uint8_t *buf)
{
return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16)
| ((uint32_t)buf[2] << 8) | (uint32_t)buf[3];
}
/*==================================================================================================
GLOBAL FUNCTION DEFINITIONS
==================================================================================================*/
/**
* @brief CRC-16/XMODEM 0x1021 0x0000
* @note CRC-16/CCITT 0xFFFF crc
*/
uint16_t SpiProtocol_CalcCrc16(const uint8_t *data, uint16_t len)
{
static const uint16_t crc_table[256] =
{
0x0000u, 0x1021u, 0x2042u, 0x3063u, 0x4084u, 0x50A5u, 0x60C6u, 0x70E7u,
0x8108u, 0x9129u, 0xA14Au, 0xB16Bu, 0xC18Cu, 0xD1ADu, 0xE1CEu, 0xF1EFu,
0x1231u, 0x0210u, 0x3273u, 0x2252u, 0x52B5u, 0x4294u, 0x72F7u, 0x62D6u,
0x9339u, 0x8318u, 0xB37Bu, 0xA35Au, 0xD3BDu, 0xC39Cu, 0xF3FFu, 0xE3DEu,
0x2462u, 0x3443u, 0x0420u, 0x1401u, 0x64E6u, 0x74C7u, 0x44A4u, 0x5485u,
0xA56Au, 0xB54Bu, 0x8528u, 0x9509u, 0xE5EEu, 0xF5CFu, 0xC5ACu, 0xD58Du,
0x3653u, 0x2672u, 0x1611u, 0x0630u, 0x76D7u, 0x66F6u, 0x5695u, 0x46B4u,
0xB75Bu, 0xA77Au, 0x9719u, 0x8738u, 0xF7DFu, 0xE7FEu, 0xD79Du, 0xC7BCu,
0x48C4u, 0x58E5u, 0x6886u, 0x78A7u, 0x0840u, 0x1861u, 0x2802u, 0x3823u,
0xC9CCu, 0xD9EDu, 0xE98Eu, 0xF9AFu, 0x8948u, 0x9969u, 0xA90Au, 0xB92Bu,
0x5AF5u, 0x4AD4u, 0x7AB7u, 0x6A96u, 0x1A71u, 0x0A50u, 0x3A33u, 0x2A12u,
0xDBFDu, 0xCBDCu, 0xFBBFu, 0xEB9Eu, 0x9B79u, 0x8B58u, 0xBB3Bu, 0xAB1Au,
0x6CA6u, 0x7C87u, 0x4CE4u, 0x5CC5u, 0x2C22u, 0x3C03u, 0x0C60u, 0x1C41u,
0xEDAEu, 0xFD8Fu, 0xCDECu, 0xDDCDu, 0xAD2Au, 0xBD0Bu, 0x8D68u, 0x9D49u,
0x7E97u, 0x6EB6u, 0x5ED5u, 0x4EF4u, 0x3E13u, 0x2E32u, 0x1E51u, 0x0E70u,
0xFF9Fu, 0xEFBEu, 0xDFDDu, 0xCFFCu, 0xBF1Bu, 0xAF3Au, 0x9F59u, 0x8F78u,
0x9188u, 0x81A9u, 0xB1CAu, 0xA1EBu, 0xD10Cu, 0xC12Du, 0xF14Eu, 0xE16Fu,
0x1080u, 0x00A1u, 0x30C2u, 0x20E3u, 0x5004u, 0x4025u, 0x7046u, 0x6067u,
0x83B9u, 0x9398u, 0xA3FBu, 0xB3DAu, 0xC33Du, 0xD31Cu, 0xE37Fu, 0xF35Eu,
0x02B1u, 0x1290u, 0x22F3u, 0x32D2u, 0x4235u, 0x5214u, 0x6277u, 0x7256u,
0xB5EAu, 0xA5CBu, 0x95A8u, 0x8589u, 0xF56Eu, 0xE54Fu, 0xD52Cu, 0xC50Du,
0x34E2u, 0x24C3u, 0x14A0u, 0x0481u, 0x7466u, 0x6447u, 0x5424u, 0x4405u,
0xA7DBu, 0xB7FAu, 0x8799u, 0x97B8u, 0xE75Fu, 0xF77Eu, 0xC71Du, 0xD73Cu,
0x26D3u, 0x36F2u, 0x0691u, 0x16B0u, 0x6657u, 0x7676u, 0x4615u, 0x5634u,
0xD94Cu, 0xC96Du, 0xF90Eu, 0xE92Fu, 0x99C8u, 0x89E9u, 0xB98Au, 0xA9ABu,
0x5844u, 0x4865u, 0x7806u, 0x6827u, 0x18C0u, 0x08E1u, 0x3882u, 0x28A3u,
0xCB7Du, 0xDB5Cu, 0xEB3Fu, 0xFB1Eu, 0x8BF9u, 0x9BD8u, 0xABBBu, 0xBB9Au,
0x4A75u, 0x5A54u, 0x6A37u, 0x7A16u, 0x0AF1u, 0x1AD0u, 0x2AB3u, 0x3A92u,
0xFD2Eu, 0xED0Fu, 0xDD6Cu, 0xCD4Du, 0xBDAAu, 0xAD8Bu, 0x9DE8u, 0x8DC9u,
0x7C26u, 0x6C07u, 0x5C64u, 0x4C45u, 0x3CA2u, 0x2C83u, 0x1CE0u, 0x0CC1u,
0xEF1Fu, 0xFF3Eu, 0xCF5Du, 0xDF7Cu, 0xAF9Bu, 0xBFBAu, 0x8FD9u, 0x9FF8u,
0x6E17u, 0x7E36u, 0x4E55u, 0x5E74u, 0x2E93u, 0x3EB2u, 0x0ED1u, 0x1EF0u
};
uint16_t crc = 0x0000u;
uint16_t i;
for (i = 0u; i < len; i++)
{
crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)((crc >> 8) ^ data[i])]);
}
return crc;
}
/*==================================================================================================
* SpiProtocol_Pack
*==================================================================================================*/
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)
{
uint16_t total_len = 0u;
uint16_t payload_bytes;
uint16_t crc_offset;
uint16_t crc_val;
uint8_t i;
uint16_t offset;
/*———— 参数校验 ————*/
if ((frame == NULL) || ((tlvs == NULL) && (tlv_count > 0u)))
{
return SPI_PROTO_ERR_PARAM;
}
if ((frame_size != SPI_PROTO_FRAME_64) &&
(frame_size != SPI_PROTO_FRAME_128) &&
(frame_size != SPI_PROTO_FRAME_256) &&
(frame_size != SPI_PROTO_FRAME_512) &&
(frame_size != SPI_PROTO_FRAME_1024))
{
return SPI_PROTO_ERR_SIZE;
}
if (tlv_count > SPI_PROTO_MAX_TLV_COUNT)
{
return SPI_PROTO_ERR_PKTCOUNT_OVF;
}
/* 计算 TotalLen所有 TLV value 长度之和) */
for (i = 0u; i < tlv_count; i++)
{
total_len = (uint16_t)(total_len + tlvs[i].length);
}
/* Payload 总字节数 = PacketCount * 4 + TotalLen */
payload_bytes = (uint16_t)((uint16_t)tlv_count * SPI_PROTO_TLV_HEAD_LEN) + total_len;
/* 检查是否超出帧容量 */
if (payload_bytes > (uint16_t)(frame_size - SPI_PROTO_OVERHEAD))
{
return SPI_PROTO_ERR_TOTALLEN_OVF;
}
/*———— 写入帧 ————*/
(void)memset(frame, 0x00u, frame_size);
/* SOF */
frame[0] = SPI_PROTO_SOF;
/* HEAD从偏移 1 开始) */
frame[1] = SPI_PROTO_VERSION; /* Version */
frame[2] = frame_type; /* FrameType */
SpiProtocol_WriteBe16(&frame[3], seq); /* Seq */
SpiProtocol_WriteBe32(&frame[5], timestamp); /* Timestamp */
frame[9] = tlv_count; /* PacketCount */
SpiProtocol_WriteBe16(&frame[10], total_len); /* TotalLen */
/* Payload — 逐 TLV 写入 */
offset = SPI_PROTO_OVERHEAD - 1u; /* 11 + 4 - 1 = offset of first TLV after SOF+HEAD = offset 11 */
/* 实际上 SOF(1) + HEAD(11) = 12 字节在 SOF+HEAD 区域Payload 从 offset 110-based开始 */
/* offset 11 = SOF(1) + HEAD(11) */
offset = 1u + SPI_PROTO_HEAD_LEN; /* = 12 */
for (i = 0u; i < tlv_count; i++)
{
frame[offset] = tlvs[i].service_id;
frame[offset + 1u] = tlvs[i].method_id;
SpiProtocol_WriteBe16(&frame[offset + 2u], tlvs[i].length);
offset = (uint16_t)(offset + SPI_PROTO_TLV_HEAD_LEN);
if (tlvs[i].length > 0u)
{
(void)memcpy(&frame[offset], tlvs[i].value, tlvs[i].length);
offset = (uint16_t)(offset + tlvs[i].length);
}
}
/* CRC16 — 计算 HEAD + Payload */
crc_offset = offset; /* offset 当前指向 CRC 写入位置 */
crc_val = SpiProtocol_CalcCrc16(&frame[1], (uint16_t)(crc_offset - 1u));
SpiProtocol_WriteBe16(&frame[crc_offset], crc_val);
offset = (uint16_t)(crc_offset + 2u);
/* EOF */
frame[offset] = SPI_PROTO_EOF;
/* offset = (uint16_t)(offset + 1u); — padding 已在 memset 中填充 */
/* 返回帧长(= frame_size已 memset 填充 0x00 至末尾) */
return (int32_t)frame_size;
}
/*==================================================================================================
* SpiProtocol_Unpack
*==================================================================================================*/
int32_t SpiProtocol_Unpack(const uint8_t *frame, uint16_t frame_len,
uint16_t frame_size,
SpiProtocol_RxResultType *result)
{
uint16_t calc_crc;
uint16_t recv_crc;
uint16_t total_len;
uint8_t packet_count;
SpiProtocol_FrameType frame_type;
uint16_t seq;
uint32_t timestamp;
uint16_t offset;
uint16_t min_frame_len;
uint16_t payload_bytes;
uint16_t crc_pos;
uint16_t eof_pos;
uint8_t i;
uint16_t t;
/*———— 参数校验 ————*/
if ((frame == NULL) || (result == NULL))
{
return SPI_PROTO_ERR_PARAM;
}
/* 帧至少要有 SOF + HEAD + CRC + EOF = 15 字节 */
min_frame_len = SPI_PROTO_OVERHEAD;
if (frame_len < min_frame_len)
{
return SPI_PROTO_ERR_FRAME_SHORT;
}
/* SOF 校验 */
if (frame[0] != SPI_PROTO_SOF)
{
return SPI_PROTO_ERR_SOF_MISMATCH;
}
/* Version 校验 */
if (frame[1] != SPI_PROTO_VERSION)
{
return SPI_PROTO_ERR_VERSION_MISMATCH;
}
/* 解析 HEAD 字段 */
frame_type = (SpiProtocol_FrameType)frame[2];
seq = SpiProtocol_ReadBe16(&frame[3]);
timestamp = SpiProtocol_ReadBe32(&frame[5]);
packet_count = frame[9];
total_len = SpiProtocol_ReadBe16(&frame[10]);
/* PacketCount 校验 */
if (packet_count > SPI_PROTO_MAX_TLV_COUNT)
{
return SPI_PROTO_ERR_PKTCOUNT_OVF;
}
/* 计算 Payload 字节数 */
payload_bytes = (uint16_t)((uint16_t)packet_count * SPI_PROTO_TLV_HEAD_LEN) + total_len;
/* 计算 CRC / EOF 位置 */
crc_pos = (uint16_t)(1u + SPI_PROTO_HEAD_LEN + payload_bytes);
eof_pos = (uint16_t)(crc_pos + 2u);
/* 检查帧长度是否足够 */
if ((uint16_t)(eof_pos + 1u) > frame_len)
{
return SPI_PROTO_ERR_FRAME_SHORT;
}
/* EOF 校验 */
if (frame[eof_pos] != SPI_PROTO_EOF)
{
return SPI_PROTO_ERR_EOF_MISMATCH;
}
/* CRC 校验 */
recv_crc = SpiProtocol_ReadBe16(&frame[crc_pos]);
calc_crc = SpiProtocol_CalcCrc16(&frame[1], crc_pos - 1u);
if (recv_crc != calc_crc)
{
return SPI_PROTO_ERR_CRC_MISMATCH;
}
/* Padding 校验EOF 之后到 frame_len 或 frame_size 必须是 0x00 */
{
uint16_t pad_end = (frame_size > 0u) ? frame_size : frame_len;
if (pad_end > (uint16_t)(eof_pos + 1u))
{
for (t = (uint16_t)(eof_pos + 1u); t < pad_end; t++)
{
if (t < frame_len)
{
if (frame[t] != 0x00u)
{
return SPI_PROTO_ERR_PADDING_NZ;
}
}
}
}
}
/*———— 填充结果 ————*/
result->frame_type = frame_type;
result->seq = seq;
result->timestamp = timestamp;
result->tlv_count = packet_count;
result->nack_error_code = 0u;
/* 解析 TLV */
offset = 1u + SPI_PROTO_HEAD_LEN; /* 跳过 SOF + HEAD */
for (i = 0u; i < packet_count; i++)
{
result->tlvs[i].service_id = frame[offset];
result->tlvs[i].method_id = frame[offset + 1u];
result->tlvs[i].length = SpiProtocol_ReadBe16(&frame[offset + 2u]);
result->tlvs[i].value = &frame[offset + SPI_PROTO_TLV_HEAD_LEN];
offset = (uint16_t)(offset + SPI_PROTO_TLV_HEAD_LEN + result->tlvs[i].length);
}
/* 如果是 NACK 帧,提取错误码 */
if ((frame_type == SPI_PROTO_FRAME_NACK) && (packet_count == 1u))
{
if ((result->tlvs[0].service_id == SPI_PROTO_SID_ERROR) &&
(result->tlvs[0].length >= 1u))
{
result->nack_error_code = result->tlvs[0].value[0];
}
}
return (int32_t)packet_count;
}
/*==================================================================================================
* SpiProtocol_PackAck ACK
*==================================================================================================*/
int32_t SpiProtocol_PackAck(uint8_t *frame, uint16_t frame_size, uint16_t ack_seq)
{
/* ACK: FrameType=ACK, PacketCount=0, TotalLen=0, 无 TLV */
return SpiProtocol_Pack(frame, frame_size,
SPI_PROTO_FRAME_ACK, ack_seq, 0u,
NULL, 0u);
}
/*==================================================================================================
* SpiProtocol_PackNack NACK
*==================================================================================================*/
int32_t SpiProtocol_PackNack(uint8_t *frame, uint16_t frame_size,
uint16_t ack_seq, uint8_t error_code)
{
SpiProtocol_TlvType tlv;
tlv.service_id = SPI_PROTO_SID_ERROR;
tlv.method_id = 0x00u;
tlv.length = 1u;
tlv.value = &error_code;
return SpiProtocol_Pack(frame, frame_size,
SPI_PROTO_FRAME_NACK, ack_seq, 0u,
&tlv, 1u);
}
/*==================================================================================================
* SpiProtocol_PackHeartbeat
*==================================================================================================*/
int32_t SpiProtocol_PackHeartbeat(uint8_t *frame, uint16_t frame_size, uint16_t seq)
{
return SpiProtocol_Pack(frame, frame_size,
SPI_PROTO_FRAME_HEARTBEAT, seq, 0u,
NULL, 0u);
}
/** @} */