Line data Source code
1 : /********************************************************************************
2 : * Copyright (c) 2026 Accenture
3 : *
4 : * This program and the accompanying materials are made available under the
5 : * terms of the Apache License Version 2.0 which is available at
6 : * https://www.apache.org/licenses/LICENSE-2.0
7 : *
8 : * SPDX-License-Identifier: Apache-2.0
9 : ********************************************************************************/
10 :
11 : #pragma once
12 :
13 : #include "someip/ISomeIpSerializable.h"
14 : #include "someip/SomeIpStreamer.h"
15 :
16 : #include <etl/span.h>
17 : #include <etl/unaligned_type.h>
18 : #include <cmath>
19 :
20 : namespace someip
21 : {
22 : /**
23 : * The SomeIpSerializer class provides an easy way to serialize Some/IP
24 : * types into raw bytes. This class also provides a helper function for
25 : * writing out a length field. The class is created with a buffer to
26 : * ensure that buffer overwrites do not happen. If a serializer object
27 : * enters an error state all subsequent writes will be empty operations;
28 : * they will not cause other problems.
29 : *
30 : * \section SomeIpSerializer_example Usage example
31 : * \code{.cpp}
32 : * void serialize(::etl::span<uint8_t> target, const ISomeIpSerializable& obj)
33 : * {
34 : * SomeIpSerializer serializer(target);
35 : *
36 : * // create a promise so we can write the length when we are done
37 : * {
38 : * LengthHelper<uint8_t> promise(serializer);
39 : *
40 : * size_t position = serializer.getCurrentPosition();
41 : *
42 : * // write out the object
43 : * serializer << obj;
44 : *
45 : * // The length will be written when the LengthHelper goes out of scope.
46 : * }
47 : * // write more data
48 : * serializer << uint32_t(42);
49 : * }
50 : * \endcode
51 : */
52 : class SomeIpSerializer : public SomeIpStreamer
53 : {
54 : public:
55 : /**
56 : * Create a new SomeIpSerializer that uses the specified buffer.
57 : *
58 : * \param buffer The buffer the serializer will use to write bytes.
59 : */
60 : explicit SomeIpSerializer(::etl::span<uint8_t> buffer);
61 :
62 : /**
63 : * Returns the underlying payload as a const buffer.
64 : */
65 11 : ::etl::span<uint8_t const> getPayload() const { return _buffer.first(_currentPos); }
66 :
67 140 : size_t getCurrentPosition() const { return _currentPos; }
68 :
69 : /**
70 : * Returns how much more data can be written.
71 : */
72 21 : size_t bytesAvailable() const { return _buffer.size() - _currentPos; }
73 :
74 : /**
75 : * Writes out a bool value. The value is converted to a uint8_t and
76 : * then written to the byte buffer.
77 : *
78 : * \param item The boolean value to write.
79 : *
80 : * \note If the serializer is in an error state then no value will be written
81 : * to the buffer. If there is no space for the value then the serializer will
82 : * set to an error state.
83 : */
84 2 : void operator<<(bool const item) { write_byte(item); }
85 :
86 : /**
87 : * Writes out a char value. The value is converted to a uint8_t and
88 : * then written to the byte buffer.
89 : *
90 : * \param item The char value to write.
91 : *
92 : * \note If the serializer is in an error state then no value will be written
93 : * to the buffer. If there is no space for the value then the serializer will
94 : * set to an error state.
95 : */
96 103 : void operator<<(char const item) { write_byte(item); }
97 :
98 : /**
99 : * Writes out a uint8_t value.
100 : *
101 : * \param item The uint8_t value to write.
102 : *
103 : * \note If the serializer is in an error state then no value will be written
104 : * to the buffer. If there is no space for the value then the serializer will
105 : * set to an error state.
106 : */
107 1497 : void operator<<(uint8_t const item) { write_byte(item); }
108 :
109 : /**
110 : * Writes out an int8_t value.
111 : *
112 : * \param item The int8_t value to write.
113 : *
114 : * \note If the serializer is in an error state then no value will be written
115 : * to the buffer. If there is no space for the value then the serializer will
116 : * set to an error state.
117 : */
118 3 : void operator<<(int8_t const item) { write_byte(item); }
119 :
120 : /**
121 : * Writes out a uint16_t value in the currently selected endianness.
122 : *
123 : * \param item The uint16_t value to write.
124 : *
125 : * \note If the serializer is in an error state then no value will be written
126 : * to the buffer. If there is no space for the value then the serializer will
127 : * set to an error state.
128 : */
129 13 : void operator<<(uint16_t const item) { write(item); }
130 :
131 : /**
132 : * Writes out an int16_t value in the currently selected endianness.
133 : *
134 : * \param item The int16_t value to write.
135 : *
136 : * \note If the serializer is in an error state then no value will be written
137 : * to the buffer. If there is no space for the value then the serializer will
138 : * set to an error state.
139 : */
140 3 : void operator<<(int16_t const item) { write(item); }
141 :
142 : /**
143 : * Writes out a uint32_t value in the currently selected endianness.
144 : *
145 : * \param item The uint32_t value to write.
146 : *
147 : * \note If the serializer is in an error state then no value will be written
148 : * to the buffer. If there is no space for the value then the serializer will
149 : * set to an error state.
150 : */
151 5 : void operator<<(uint32_t const item) { write(item); }
152 :
153 : /**
154 : * Writes out an int32_t value in the currently selected endianness.
155 : *
156 : * \param item The int32_t value to write.
157 : *
158 : * \note If the serializer is in an error state then no value will be written
159 : * to the buffer. If there is no space for the value then the serializer will
160 : * set to an error state.
161 : */
162 3 : void operator<<(int32_t const item) { write(item); }
163 :
164 : /**
165 : * Writes out a uint64_t value in the currently selected endianness.
166 : *
167 : * \param item The uint64_t value to write.
168 : *
169 : * \note If the serializer is in an error state then no value will be written
170 : * to the buffer. If there is no space for the value then the serializer will
171 : * set to an error state.
172 : */
173 4 : void operator<<(uint64_t const item) { write(item); }
174 :
175 : /**
176 : * Writes out an int64_t value in the currently selected endianness.
177 : *
178 : * \param item The int64_t value to write.
179 : *
180 : * \note If the serializer is in an error state then no value will be written
181 : * to the buffer. If there is no space for the value then the serializer will
182 : * set to an error state.
183 : */
184 3 : void operator<<(int64_t const item) { write(item); }
185 :
186 : /**
187 : * Writes out a float value according to the IEEE-754 standard.
188 : *
189 : * \param item The float value to write.
190 : *
191 : * \note If the serializer is in an error state then no value will be written
192 : * to the buffer. If there is no space for the value then the serializer will
193 : * set to an error state.
194 : */
195 : void operator<<(float_t item);
196 :
197 : /**
198 : * Writes out a double value according to the IEEE-754 standard.
199 : *
200 : * \param item The double value to write.
201 : *
202 : * \note If the serializer is in an error state then no value will be written
203 : * to the buffer. If there is no space for the value then the serializer will
204 : * set to an error state.
205 : */
206 : void operator<<(double_t item);
207 :
208 : /**
209 : * Writes out the ISomeIpSerializable object. This calls the
210 : * ISomeIpSerializable::serializeToArray method.
211 : *
212 : * \param item The serializable object to write.
213 : *
214 : * \note If the serializer is in an error state then no value will be written
215 : * to the buffer. If an error happens during the call to serializeToArray then
216 : * the serializer will be set to an error state. The data in the underlying buffer may
217 : * be corrupted and incomplete and should not be used.
218 : */
219 : void operator<<(ISomeIpSerializable const& item);
220 :
221 : void operator<<(::etl::span<uint8_t const> data);
222 :
223 : /**
224 : * Returns a buffer of a specified length at the current serializer position, where something
225 : * can be written later. This is used for writing sizes of dynamically sized types.
226 : *
227 : * In case the requested number of bytes is not available, an error is be set and empty slice is
228 : * returned.
229 : *
230 : * \param length The number of bytes that are requested.
231 : * \return Byte buffer at the current position.
232 : */
233 12 : ::etl::span<uint8_t> skipBytes(size_t const length)
234 : {
235 12 : size_t const start = _currentPos;
236 :
237 12 : if (!hasSpace(length))
238 : {
239 0 : return ::etl::span<uint8_t>();
240 : }
241 :
242 12 : _currentPos += length;
243 12 : return _buffer.subspan(start, length);
244 : }
245 :
246 : void writeTypeFieldSize(uint32_t fieldType);
247 :
248 : private:
249 : template<typename T>
250 31 : void write(T const item)
251 : {
252 31 : if (hasSpace(sizeof(T)) && isGood())
253 : {
254 19 : if (_bigEndian)
255 : {
256 12 : ::etl::unaligned_type_ext<T, ::etl::endian::big>{&_buffer[_currentPos]} = item;
257 : }
258 : else
259 : {
260 7 : ::etl::unaligned_type_ext<T, ::etl::endian::little>{&_buffer[_currentPos]} = item;
261 : }
262 19 : _currentPos += sizeof(T);
263 : }
264 31 : }
265 :
266 : template<typename T>
267 1605 : void write_byte(T const item)
268 : {
269 1605 : if (hasSpace(1) && isGood())
270 : {
271 1601 : _buffer[_currentPos] = static_cast<uint8_t>(item);
272 1601 : _currentPos++;
273 : }
274 1605 : }
275 :
276 1669 : bool hasSpace(size_t const length)
277 : {
278 1669 : if (_currentPos + length > _buffer.size())
279 : {
280 19 : _errorCode = ErrorCode::SOMEIP_ERROR;
281 19 : return false;
282 : }
283 :
284 1650 : return true;
285 : }
286 :
287 : ::etl::span<uint8_t> _buffer;
288 : size_t _currentPos;
289 : };
290 :
291 : } // namespace someip
|