SOME/IP 序列化问题
SOMEIP报文分为Header和Payload两部分,如下图。

其中Payload部分,在Serialize后会在Payload头部填充TLV Tag(4Byte)和BOM(3Byte)。



传输的字符串是someData.Data = "aaaaaaaaaaaaaaaaaaaa"; 20个a
payload中 00 00 00 18 ef bb bf
前面一部分是00 00 00 18 (十六进制的18)
ef bb bf 对应的是BOM[0] BOM[1] BOM[2]
说明: BOM+实际数据的长度 = 24(BOM 3个字节 + 20个a + 1个 \0)
即使hasTlvTag确实是false,也会保留这个位置,只是里面填写00

import AUTOSAR.StdTypes.uint8_t
import AUTOSAR.StdTypes.stringpackage etas.com {interface AraCM_TLV namespace etas.com {event DataPublisher of DataMessagemethod DataIO (in message (tlvId:33) of string, out value(tlvId:44) of uint8_t)} // if tlv is configured, all members must have tlvids and the ids are unique struct DataMessage {DataArray(tlvId:11) of optional<array<uint8_t, 256>>DataString(tlvId:22) of optional<string>} /* The definition of Software Components in the Application Design including the provided and required ports categorized by the relevant ServiceInterfaces are now mandatory for the services definition. */ component Publisher_Component {provide PPort for AraCM_TLV}component Subscriber_Component {require RPort for AraCM_TLV}
}
Method ID =7f ----> 127


https://blog.csdn.net/hammershr2012/article/details/131073325
/*** \\file aracm_event_serializer.h** \\authors This file was generated with VRTE Flexible Safety - Manifest to Adaptive Runtime API Generator * * \\brief Header File for service specific serializer**/#ifndef ETAS_COM_ARACM_EVENT_SERIALIZER_HPP_INCLUDED
#define ETAS_COM_ARACM_EVENT_SERIALIZER_HPP_INCLUDED#include "etas/com/aracm_event_common.h"#include "serializer/SerializerUtils.hpp"
#include "serializer/SerializeBasicTypes.hpp"
#include "serializer/DeserializeBasicTypes.hpp"
#include "serializer/IDeserializer.hpp"
#include "serializer/ISerializer.hpp"#include <cstring>namespace etas {
namespace com {
namespace aracm_event_SD {
// RULECHECKER_comment(2, 1, check_single_use_pod_variable, "Variable used for possible creation of interface components.", true)
// coverity[autosar_cpp14_a0_1_1_violation:FALSE] Variable used for possible creation of interface components.
static constexpr uint8_t sizeUnionTypeField{1U};
// RULECHECKER_comment(2, 1, check_single_use_pod_variable, "Variable used for possible creation of interface components.", true)
// coverity[autosar_cpp14_a0_1_1_violation:FALSE] Variable used for possible creation of interface components.
static constexpr ::com::serializer::SerializerSettings someipSettings {::com::serializer::ByteOrder::kBigEndian,4U,4U,4U,4U,0U,4U,false};// Note: For TLV-enabled IPC deployments where struct data types are used, the value of the size of the struct length
// field will be overwritten to 4 bytes. This is done to include a length field for handling optional members,
// simplifying the implementation by using a 4-byte length field for all TLV-structs. Even though the value is set to 0
// here, it will be modified during runtime if the conditions for TLV serialization are met.
// RULECHECKER_comment(2, 1, check_single_use_pod_variable, "Variable used for possible creation of interface components.", true)
// coverity[autosar_cpp14_a0_1_1_violation:FALSE] Variable used for possible creation of interface components.
static constexpr ::com::serializer::SerializerSettings ipcSettings {::com::serializer::ByteOrder::kOpaque,4U,0U,4U,4U,0U,4U,false};class Serializer_DataPublisher : public ::com::serializer::ISerializer<DataMessage>
{
private:::com::serializer::SerializerSettings settings_;ara::com::DeploymentType deploymentType_;public:Serializer_DataPublisher(::com::serializer::SerializerSettings settings, ara::com::DeploymentType deploymentType) : ::com::serializer::ISerializer<DataMessage>(), settings_(settings), deploymentType_(deploymentType){}private:// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, a serializer with a void sampleType is used. Refactor in #72627.// coverity[autosar_cpp14_a0_1_3_violation:FALSE] The method is used.uint32_t computeSerializedSize(const DataMessage* objectp, uint8_t& lengthFieldSize, const bool hasTlvTag){uint32_t length{0U};
// // coverity[autosar_cpp14_a4_7_1_violation] Since the inputs are guaranteed not to exceed the maximum range of uint32_t, the calculation will not cause wrap-around.
// length += ::com::serializer::computeSerializedSize(objectp->Data, settings_); // STRING
// // coverity[autosar_cpp14_a0_1_1_violation:FALSE] The variable is used.
// lengthFieldSize = (settings_.isDynamicLengthFieldSize && hasTlvTag) ? ::com::serializer::computeSizeOfLengthField(length) : settings_.sizeStructLengthField;
// // coverity[autosar_cpp14_a4_7_1_violation] Since the inputs are guaranteed not to exceed the maximum range of uint32_t, the calculation will not cause wrap-around.
// length += lengthFieldSize;length = objectp->Data.length() + 1;
// std::cout << "=================================================" << std::endl;
// std::cout << "31. length = " << length << std::endl;return length;}public:// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627.// coverity[autosar_cpp14_a0_1_3_violation:FALSE] The method is used.uint32_t computeSerializedSize(const DataMessage* objectp) override{// coverity[autosar_cpp14_m3_4_1_violation] The declaration is preferred here for better readability and maintainance.// coverity[autosar_cpp14_a0_1_1_violation] The variable is used.uint8_t lengthFieldSize{0U};return computeSerializedSize(objectp, lengthFieldSize, false);}// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627.// coverity[autosar_cpp14_a0_1_3_violation:FALSE] The method is used.uint32_t computeSerializedSizeTlv(const DataMessage* objectp, uint8_t &lengthFieldSizeOut) override{return computeSerializedSize(objectp, lengthFieldSizeOut, true);}private:// RULECHECKER_comment(4, 1, check_max_cyclomatic_complexity, "Generated code, the number of cyclomatic complexity is not relevant. For understandability, do not modify.", true)// RULECHECKER_comment(3, 1, check_max_instructions, "Generated code, the number of instructions is not relevant. For understandability, do not modify.", true)// RULECHECKER_comment(2, 1, check_max_parameters, "Generated code, the number of parameters complexity is not relevant.", true)// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627./*bool serialize(uint8_t* targetbuffer, uint32_t maxsize, const DataMessage* objectp, const bool hasTlvTag){// coverity[autosar_cpp14_a0_1_1_violation:FALSE] The value assigned to the variable is used.uint32_t length{0U};uint32_t total_written{0U};// coverity[autosar_cpp14_m3_4_1_violation] The declaration is preferred here for better readability and maintainance.// coverity[autosar_cpp14_a0_1_1_violation] The variable is used.uint8_t lengthFieldSize{0U};// Ensure that the buffer has enough space for the struct size that we want to prepend at the end// coverity[autosar_cpp14_m3_4_1_violation] The declaration is preferred here for better readability and maintainance.// coverity[autosar_cpp14_a0_1_1_violation] The variable is used.total_written = (settings_.isDynamicLengthFieldSize && hasTlvTag) ? 0U : settings_.sizeStructLengthField;// serialize STRING of type stringlength = ::com::serializer::computeSerializedSize(objectp->Data, settings_);// coverity[autosar_cpp14_a4_7_1_violation] Since the inputs are guaranteed not to exceed the maximum range of uint32_t, the calculation will not cause wrap-around.if ((length + total_written) > maxsize){return false;}// coverity[autosar_cpp14_m5_0_15_violation:FALSE] The pointer is arithmetic happens here only with indexing operator, which is compliant.if (!::com::serializer::serialize(objectp->Data, &targetbuffer[total_written], length, settings_)){return false;}// coverity[autosar_cpp14_a0_1_1_violation:FALSE] The value assigned to the variable is used.total_written += length;if (settings_.isDynamicLengthFieldSize && hasTlvTag){// coverity[autosar_cpp14_a0_1_1_violation:FALSE] The variable is used.lengthFieldSize = ::com::serializer::computeSizeOfLengthField(total_written);// Check if there is enough space to prepend the length field// coverity[autosar_cpp14_a4_7_1_violation] Since the inputs are guaranteed not to exceed the maximum range of uint32_t, the calculation will not cause wrap-around.if (lengthFieldSize + total_written > maxsize){return false;}// Shift the serialized data to make space for the length field// coverity[autosar_cpp14_m5_0_15_violation] The pointer is managed by std::memmove in this case. No workaround when using C-style pointers.std::memmove(targetbuffer + lengthFieldSize, targetbuffer, total_written);if(!::com::serializer::writeLengthField(lengthFieldSize, total_written, &targetbuffer, settings_.byteOrder)){return false;}}else if (0U != settings_.sizeStructLengthField){// coverity[autosar_cpp14_a0_1_1_violation:FALSE] The variable is used.lengthFieldSize = settings_.sizeStructLengthField;// Subtract the length field size from total_written before writing// coverity[autosar_cpp14_a4_7_1_violation] Since the inputs are guaranteed not to exceed the maximum range of uint32_t, the calculation will not cause wrap-around.total_written -= lengthFieldSize;if (!::com::serializer::writeLengthField(lengthFieldSize, total_written, &targetbuffer, settings_.byteOrder)){return false;}}return true;}*//*** @brief 将 DataMessage 对象序列化到目标缓冲区。** 此函数将 objectp->Data 字符串的内容复制到 targetbuffer 中,* 并在末尾添加空终止符。它会检查缓冲区大小以防止溢出。** @param targetbuffer 指向目标缓冲区的指针。* @param maxsize 目标缓冲区的最大大小。* @param objectp 指向要序列化的 DataMessage 对象的指针。* @param hasTlvTag (当前实现中未使用,保留以匹配原函数签名)* @return 如果序列化成功则返回 true,如果缓冲区太小则返回 false。*/bool serialize(uint8_t* targetbuffer, uint32_t maxsize, const DataMessage* objectp, const bool hasTlvTag){// 忽略未使用的参数,避免编译器警告(void)hasTlvTag;// 检查输入有效性if (!targetbuffer || !objectp || maxsize == 0) {std::cout << "serialize invalid data " << std::endl;std::cout << "maxsize = " << maxsize << std::endl;return false;}// 获取数据长度uint32_t data_length = static_cast<uint32_t>(objectp->Data.length());
// std::cout << "=====================================================" << std::endl;
// std::cout << "1. data_length = " << data_length << std::endl;
// std::cout << "2. maxsize = " << maxsize << std::endl;
// std::cout << "3. hasTlvTag = " << hasTlvTag << std::endl;std::memcpy(targetbuffer, objectp->Data.c_str(), data_length);targetbuffer[data_length+1] = '\0';return true;}public:/* RULECHECKER_comment(2, 1, check_max_parameters, "Generated code, the number of parameters complexity is not relevant.", true) */// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627.// coverity[autosar_cpp14_a0_1_3_violation:FALSE] This function is called by serialize function of public.bool serialize(uint8_t* targetbuffer, uint32_t maxsize, const DataMessage* objectp) override{return serialize(targetbuffer, maxsize, objectp, false);}/* RULECHECKER_comment(2, 1, check_max_parameters, "Generated code, the number of parameters complexity is not relevant.", true) */// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627.// coverity[autosar_cpp14_a0_1_3_violation:FALSE] This function is called by serialize function of public.bool serializeTlv(uint8_t* targetbuffer, uint32_t maxsize, const DataMessage* objectp) override{return serialize(targetbuffer, maxsize, objectp, true);}
};class Deserializer_DataPublisher : public ::com::serializer::IDeserializer<DataMessage>
{
private:::com::serializer::SerializerSettings settings_;ara::com::DeploymentType deploymentType_;public:Deserializer_DataPublisher(::com::serializer::SerializerSettings settings, ara::com::DeploymentType deploymentType) : ::com::serializer::IDeserializer<DataMessage>(), settings_(settings), deploymentType_(deploymentType){}private:/* RULECHECKER_comment(2, 1, check_max_parameters, "Generated code, the number of parameters complexity is not relevant.", true) */// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627.// bool deserialize(const uint8_t* receivebuffer, uint32_t length, DataMessage* objectp, uint32_t& readbytes, uint8_t lengthFieldSize)
// {
// uint32_t readLength{0U};
// // coverity[autosar_cpp14_a0_1_1_violation:FALSE] The value assigned to the variable is used.
// uint32_t subreadbytes{0U};
// // coverity[autosar_cpp14_a0_1_1_violation:FALSE] The value assigned to the variable is used.
// uint32_t structLength{0U};
//
// if (0U == lengthFieldSize)
// {
// // coverity[autosar_cpp14_a0_1_1_violation:FALSE] The variable is used.
// lengthFieldSize = settings_.sizeStructLengthField;
// }
//
// if (lengthFieldSize > length)
// {
// return false;
// }
// // coverity[autosar_cpp14_m0_1_9_violation] The else case for no length field not needed: The static length field size must be non-zero for TLV during configuration.
// // coverity[autosar_cpp14_m0_1_2_violation] The else case for no length field not needed: The static length field size must be non-zero for TLV during configuration.
// if (0U != lengthFieldSize)
// {
// ::com::serializer::readLengthField(lengthFieldSize, structLength, &receivebuffer, settings_.byteOrder);
// // coverity[autosar_cpp14_a0_1_1_violation:FALSE] The variable is used.
// // coverity[autosar_cpp14_m0_1_9_violation:FALSE] The variable is used.
// length -= lengthFieldSize;
// }
//
// // coverity[autosar_cpp14_m5_0_15_violation:FALSE] The pointer is arithmetic happens here only with indexing operator, which is compliant.
// // coverity[autosar_cpp14_m5_0_15_violation:FALSE] The pointer is arithmetic happens here only with indexing operator, which is compliant.
// if (!::com::serializer::deserialize(objectp->Data, &receivebuffer[readLength], length - readLength, settings_, subreadbytes))
// {
// return false;
// }
// readLength += subreadbytes;
// if (0U != lengthFieldSize)
// {
// /* If there is any additional data at the end of the struct that the receiver does not recognize,
// * the data will be discarded and the deserialize function will return true (SWS_CM_10219).
// * If there is not enough data to deserialize, the deserialize function will return false. */
// if (readLength > structLength)
// {
// // coverity[autosar_cpp14_m0_1_2_violation] The code is reachable when there is not enough data to deserialize.
// return false;
// }
// readbytes = structLength + lengthFieldSize;
// }
// else
// {
// // coverity[autosar_cpp14_m0_1_9_violation] If the length of the field or struct field is 0, this code block will be reached.
// // coverity[autosar_cpp14_m0_1_2_violation] If deserialization happens successfully, this code block will be reached.
// readbytes = readLength;
// }
//
// return true;
// }bool deserialize(const uint8_t* receivebuffer, uint32_t length, DataMessage* objectp, uint32_t& readbytes, uint8_t lengthFieldSize){// 忽略未使用的参数,避免编译器警告(void)lengthFieldSize;// 检查输入有效性if (!receivebuffer || !objectp || length == 0) {readbytes = 0;return false;}// 在指定长度范围内查找字符串终止符 '\0'const void* null_pos = std::memchr(receivebuffer, '\0', length);// 如果未找到终止符,则输入数据无效或不完整if (null_pos == nullptr) {readbytes = 0; // 或者可以设为 length,取决于错误处理策略return false;}// 计算字符串长度(不包括终止符)uint32_t str_length = static_cast<uint32_t>(static_cast<const uint8_t*>(null_pos) - receivebuffer);// 使用构造函数或 assign 方法一次性设置字符串,效率更高// 注意:str_length 已经是不包含 '\0' 的长度objectp->Data.assign(reinterpret_cast<const char*>(receivebuffer), str_length);// 计算总共读取的字节数(包括终止符 '\0')readbytes = str_length + 1;return true;}public:/* RULECHECKER_comment(3, 1, check_max_parameters, "Generated code, the number of parameters complexity is not relevant.", true) */// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627.// coverity[autosar_cpp14_a0_1_3_violation:FALSE] This function is called by deserialize function of public.bool deserialize(const uint8_t* receivebuffer, uint32_t length, DataMessage* objectp, uint32_t& readbytes) override{return deserialize(receivebuffer, length, objectp, readbytes, 0U);}/* RULECHECKER_comment(3, 1, check_max_parameters, "Generated code, the number of parameters complexity is not relevant.", true) */// coverity[autosar_cpp14_a8_4_10_violation] Changing this to a reference causes a compiler error: "Forming reference to void." This is because for methods that have no return type, we use a serializer with a void sampleType. Refactor in #72627.// coverity[autosar_cpp14_a0_1_3_violation:FALSE] This function is called by deserialize function of public.bool deserializeTlv(const uint8_t* receivebuffer, uint32_t length, DataMessage* objectp, uint32_t& readbytes, uint8_t lengthFieldSize) override{return deserialize(receivebuffer, length, objectp, readbytes, lengthFieldSize);}
};} // namespace aracm_event_SD
} // namespace com
} // namespace etas#endif // ETAS_COM_ARACM_EVENT_SERIALIZER_HPP_INCLUDED
- 代码生成后,手动修改序列化的代码
- 修改完代码后需要把图中的这一行注释掉

3)编译命令:
rvbuild -sd AraCM_Event_String/ 20
rvbuild -ld AraCM_Event_String/ 21
4)结果:

