@@ -39,6 +39,8 @@ template <typename Uart = hal::DefaultUart,
3939 types::size MaxMsgSize = 256 >
4040class Protocol
4141{
42+ static_assert (MaxMsgSize >= sizeof (VERSION ), " MaxMsgSize must be >= VERSION size" );
43+
4244public:
4345 Protocol () = default ;
4446 ~Protocol () = default ;
@@ -100,11 +102,13 @@ class Protocol
100102 if (result != Result::SUCCESS )
101103 continue ;
102104
105+ const SystemMsgType msg_type = static_cast <SystemMsgType>(frame.header .type .value );
106+
103107 if (frame.header .ack .ack_required )
104- send_ack (frame.header .ack .frame_id );
108+ send_ack (frame.header .ack .frame_id , msg_type == SystemMsgType:: VERSION_CHECK );
105109
106- // Skip HEARTBEAT frames
107- if (frame. header . type . value == static_cast <types:: u8 >( SystemMsgType::HEARTBEAT ) )
110+ // Skip HEARTBEAT and VERSION_CHECK frames
111+ if (msg_type == SystemMsgType:: HEARTBEAT || msg_type == SystemMsgType::VERSION_CHECK )
108112 {
109113 result = Result::SYS_MSG_HANDLED ;
110114 continue ;
@@ -148,9 +152,6 @@ class Protocol
148152 const types::u8 & retries = 3 ,
149153 const types::u32 & timeout = 200 )
150154 {
151- if (type >= 0xE0 )
152- return Result::WRONG_MSG_TYPE ;
153-
154155 tp::DataFrame frame;
155156 frame.header .type = type;
156157 frame.header .ack .ack_required = ack;
@@ -203,24 +204,51 @@ class Protocol
203204 return send (static_cast <types::u8 >(SystemMsgType::HEARTBEAT ), BufferView (), true );
204205 }
205206
207+ /* *
208+ * @brief Checks protocol version compatibility.
209+ *
210+ * @return Result::SUCCESS if compatible, otherwise error code.
211+ */
212+ Result version_check ()
213+ {
214+ Result result;
215+ result = send (static_cast <types::u8 >(SystemMsgType::VERSION_CHECK ), BufferView (), true );
216+ if (result != Result::SUCCESS )
217+ return result;
218+
219+ tp::DataFrame frame;
220+ result = frame.unpack (buffer_.subview (0 , tp::FieldHeader::SIZE + sizeof (VERSION )));
221+ if (result != Result::SUCCESS )
222+ return result;
223+
224+ if (frame.data [0 ] != VERSION [0 ])
225+ return Result::VERSION_MISMATCH ;
226+
227+ return Result::SUCCESS ;
228+ }
229+
206230private:
207231 /* *
208232 * @brief Sends an acknowledgment frame for the specified message ID.
209233 *
210234 * @param frame_id Identifier of the frame being acknowledged.
235+ * @param version Whether to include protocol version info in the acknowledgment.
211236 * @return Result::SUCCESS if acknowledgment received, otherwise error code.
212237 */
213- Result send_ack (const tp::FieldID& frame_id)
238+ Result send_ack (const tp::FieldID& frame_id, bool version = false )
214239 {
215- Result result;
240+ tp::DataFrame ack_frame;
241+ ack_frame.header .type = static_cast <types::u8 >(SystemMsgType::ACK );
242+ ack_frame.header .ack .ack_required = false ;
243+ ack_frame.header .ack .frame_id = frame_id;
216244
217- tp::FieldHeader ack_frame;
218- ack_frame. type = static_cast <types:: u8 >(SystemMsgType:: ACK );
219- ack_frame.ack . ack_required = false ;
220- ack_frame. ack . frame_id = frame_id;
245+ if (version)
246+ {
247+ ack_frame.data = BufferView ( const_cast <types:: u8 *>( VERSION ), sizeof ( VERSION )) ;
248+ }
221249
222- BufferHandler<tp::FieldHeader::SIZE + Crc::SIZE > ack_buf;
223- result = ack_frame.pack (ack_buf);
250+ BufferHandler<tp::FieldHeader::SIZE + Crc::SIZE + sizeof ( VERSION ) > ack_buf;
251+ Result result = ack_frame.pack (ack_buf);
224252 if (result != Result::SUCCESS )
225253 return result;
226254
@@ -236,7 +264,7 @@ class Protocol
236264 *
237265 * @param frame_id ID of the sent frame awaiting acknowledgment.
238266 * @param type Type of the sent frame (used for collision handling).
239- * @param timeout Maximum waiting time for acknowledgment, in milliseconds.
267+ * @param timeout Maximum waiting time for acknowledgment, in milliseconds.
240268 * @return Result::SUCCESS if acknowledgment received, otherwise error code.
241269 */
242270 Result wait_ack (const tp::FieldID& frame_id, types::u8 type, const types::u32 & timeout)
@@ -256,23 +284,29 @@ class Protocol
256284 if (result != Result::SUCCESS )
257285 return result;
258286
259- if (data_header.type .value == static_cast <types::u8 >(SystemMsgType::ACK ) &&
260- data_header.ack .frame_id == frame_id)
287+ const SystemMsgType rcv_type = static_cast <SystemMsgType>(data_header.type .value );
288+
289+ if (rcv_type == SystemMsgType::ACK && data_header.ack .frame_id == frame_id)
261290 {
262291 return Result::SUCCESS ;
263292 }
264- else if (data_header.type .value == static_cast <types::u8 >(SystemMsgType::HEARTBEAT ))
293+
294+ const bool send_sys_msg = type == static_cast <types::u8 >(SystemMsgType::HEARTBEAT ) ||
295+ type == static_cast <types::u8 >(SystemMsgType::VERSION_CHECK );
296+
297+ if (rcv_type == SystemMsgType::HEARTBEAT || rcv_type == SystemMsgType::VERSION_CHECK )
265298 {
266- send_ack (data_header.ack .frame_id );
267- if (type == static_cast <types:: u8 >(SystemMsgType:: HEARTBEAT ) )
299+ send_ack (data_header.ack .frame_id , rcv_type == SystemMsgType:: VERSION_CHECK );
300+ if (send_sys_msg )
268301 continue ;
269302 return Result::SYS_MSG_HANDLED ;
270303 }
271- else if (data_header.ack .ack_required ) // Collision
272- {
273- if (type == static_cast <types::u8 >(SystemMsgType::HEARTBEAT ))
274- continue ;
275304
305+ if (send_sys_msg)
306+ continue ;
307+
308+ if (data_header.ack .ack_required ) // Collision
309+ {
276310 switch (Collision)
277311 {
278312 case CollisionBehavior::PRIORITY_SEND :
0 commit comments