Skip to content

Commit 2f35b55

Browse files
committed
Supporting escape field when using comms::option::def::FrameLayerSeekField with SyncPrefixLayer.
1 parent 8b33ce2 commit 2f35b55

8 files changed

Lines changed: 157 additions & 8 deletions

File tree

doxygen/page_frame.dox

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@
408408
/// comms::frame::SyncPrefixLayer<
409409
/// SyncField,
410410
/// MyChecksum<TMessage, TInputMessages, TAllocationOptions>,
411-
/// comms::option::def::FrameLayerSeekField
411+
/// comms::option::def::FrameLayerSeekField<>
412412
/// >;
413413
/// @endcode
414414
/// Similar to the @ref page_frame_tutorial_checksum the @ref page_frame_tutorial_sync

include/comms/frame/SyncPrefixLayer.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "comms/frame/details/SyncPrefixLayerBase.h"
1515
#include "comms/frame/details/SyncPrefixLayerOptionsParser.h"
1616

17+
#include <algorithm>
1718
#include <iterator>
1819

1920
COMMS_MSVC_WARNING_PUSH
@@ -57,6 +58,10 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
5758
/// @brief Type of the field object used to read/write "sync" value.
5859
using Field = typename BaseImpl::Field;
5960

61+
/// @brief Type of the escape field provided via @ref comms::option::def::FrameLayerSeekField option.
62+
/// @details Same as @b void if not provided via said option.
63+
using EscField = typename ParsedOptionsInternal::EscField;
64+
6065
/// @brief Default constructor
6166
SyncPrefixLayer() = default;
6267

@@ -180,6 +185,18 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
180185
return field == Field();
181186
}
182187

188+
/// @brief Verify the validity of the escapte field provided via @ref comms::option::def::FrameLayerSeekField option.
189+
/// @details Default implementation compares read field with default constructed type. @n
190+
/// May be overridden by the extending class in case
191+
/// more complex logic is required.
192+
/// @param[out] field Field that has been read.
193+
/// @note May be non-static in the extending class
194+
template <typename TEscField>
195+
static bool verifyEscFieldValue(const TEscField& field)
196+
{
197+
return field == TEscField();
198+
}
199+
183200
/// @brief Prepare field for writing.
184201
/// @details Default implementation does nothing. @n
185202
/// May be overridden by the extending class in case
@@ -199,6 +216,12 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
199216
template <typename... TParams>
200217
using InstantOpTag = comms::details::tag::Tag2<>;
201218

219+
template <typename... TParams>
220+
using EscapeSupportedTag = comms::details::tag::Tag3<>;
221+
222+
template <typename... TParams>
223+
using NoEscapeTag = comms::details::tag::Tag4<>;
224+
202225
template <typename TMsg, typename TIter, typename TReader, typename... TExtraValues>
203226
ErrorStatus readInternal(
204227
Field& field,
@@ -230,6 +253,7 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
230253
}
231254

232255
if ((fieldEs == ErrorStatus::Success) &&
256+
(!fieldEscapedInternal(fromIter, iter)) &&
233257
(thisObj.verifyFieldValue(field))) {
234258
// Set iter to point after field
235259
iter = iterTmp;
@@ -280,6 +304,65 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
280304
auto fieldLen = static_cast<std::size_t>(std::distance(beforeReadIter, iter));
281305
return nextLayerReader.read(msg, iter, size - fieldLen, extraValues...);
282306
}
307+
308+
template <typename TIter>
309+
bool fieldEscapedInternal(TIter from, TIter to, NoEscapeTag<>)
310+
{
311+
static_cast<void>(from);
312+
static_cast<void>(to);
313+
return false;
314+
}
315+
316+
template <typename TIter>
317+
bool fieldEscapedInternal(TIter from, TIter to, EscapeSupportedTag<>)
318+
{
319+
auto dist = static_cast<std::size_t>(std::distance(from, to));
320+
dist = std::min(dist, EscField::maxLength());
321+
if (dist < EscField::minLength()) {
322+
return false;
323+
}
324+
325+
auto& thisObj = BaseImpl::thisLayer();
326+
327+
auto limitIter = to;
328+
std::advance(limitIter, -dist);
329+
330+
auto iter = to;
331+
std::advance(iter, -EscField::minLength());
332+
while (true) {
333+
auto iterTmp = iter;
334+
EscField escField;
335+
auto len = static_cast<std::size_t>(std::distance(iterTmp, to));
336+
auto es = escField.read(iterTmp, len);
337+
if ((es == comms::ErrorStatus::Success) &&
338+
(iterTmp == to) &&
339+
(thisObj.verifyEscFieldValue(escField))) {
340+
return true;
341+
}
342+
343+
if (iter == limitIter) {
344+
break;
345+
}
346+
347+
std::advance(iter, -1);
348+
}
349+
350+
return false;
351+
}
352+
353+
template <typename TIter>
354+
bool fieldEscapedInternal(TIter from, TIter to)
355+
{
356+
using EscTag =
357+
typename comms::util::LazyShallowConditional<
358+
std::is_same<EscField, void>::value
359+
>::template Type<
360+
NoEscapeTag,
361+
EscapeSupportedTag
362+
>;
363+
364+
return fieldEscapedInternal(from, to, EscTag());
365+
}
283366
};
284367

285368
namespace details

include/comms/frame/details/MsgSizeLayerBase.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class MsgSizeLayerBaseHelper
3636
TField,
3737
TNextLayer,
3838
ActualLayer,
39-
comms::option::FrameLayerDisallowReadUntilDataSplit
39+
comms::option::def::FrameLayerDisallowReadUntilDataSplit
4040
>;
4141

4242
public:

include/comms/frame/details/SyncPrefixLayerOptionsParser.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class SyncPrefixLayerOptionsParser<>
3030

3131
using ExtendingClass = void;
3232

33+
using EscField = void;
34+
3335
template <typename TLayer>
3436
using DefineExtendingClass = TLayer;
3537
};
@@ -46,11 +48,12 @@ class SyncPrefixLayerOptionsParser<comms::option::def::ExtendingClass<T>, TOptio
4648
using DefineExtendingClass = ExtendingClass;
4749
};
4850

49-
template <typename... TOptions>
50-
class SyncPrefixLayerOptionsParser<comms::option::def::FrameLayerSeekField, TOptions...> :
51+
template <typename TEscField, typename... TOptions>
52+
class SyncPrefixLayerOptionsParser<comms::option::def::FrameLayerSeekField<TEscField>, TOptions...> :
5153
public SyncPrefixLayerOptionsParser<TOptions...>
5254
{
5355
public:
56+
using EscField = TEscField;
5457
static constexpr bool HasSeekField = true;
5558
};
5659

include/comms/frame/details/SyncSuffixLayerOptionsParser.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class SyncSuffixLayerOptionsParser<>
3131

3232
using ExtendingClass = void;
3333

34+
using EscField = void;
35+
3436
template <typename TLayer>
3537
using DefineExtendingClass = TLayer;
3638
};
@@ -55,11 +57,12 @@ class SyncSuffixLayerOptionsParser<comms::option::def::ExtendingClass<T>, TOptio
5557
using DefineExtendingClass = ExtendingClass;
5658
};
5759

58-
template <typename... TOptions>
59-
class SyncSuffixLayerOptionsParser<comms::option::def::FrameLayerSeekField, TOptions...> :
60+
template <typename TEscField, typename... TOptions>
61+
class SyncSuffixLayerOptionsParser<comms::option::def::FrameLayerSeekField<TEscField>, TOptions...> :
6062
public SyncSuffixLayerOptionsParser<TOptions...>
6163
{
6264
public:
65+
using EscField = TEscField;
6366
static constexpr bool HasSeekField = true;
6467
};
6568

include/comms/options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,9 @@ using ChecksumLayerVerifyBeforeRead = FrameLayerVerifyBeforeRead;
10871087

10881088
/// @brief Force the layer to seek its field before
10891089
/// forwarding read to the wrapped layer(s).
1090+
/// @tparam TEscField - Escape field to avoid detection of the field being seeked.
10901091
/// @headerfile comms/options.h
1092+
template <typename TEscField = void>
10911093
struct FrameLayerSeekField {};
10921094

10931095
/// @brief Force field not to be serialized during read/write operations

test/SyncPrefixLayer.th

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public:
2929
void test7();
3030
void test8();
3131
void test9();
32+
void test10();
3233

3334
private:
3435

@@ -94,10 +95,22 @@ private:
9495
comms::option::DefaultNumValue<0xabcd>
9596
>;
9697

98+
template <typename TField, std::size_t TSize>
99+
using EscField =
100+
comms::field::IntValue<
101+
TField,
102+
unsigned,
103+
comms::option::FixedLength<TSize>,
104+
comms::option::DefaultNumValue<0xdead>
105+
>;
106+
97107
template <typename TField>
98108
using SyncField2 = SyncField<TField, 2>;
109+
template <typename TField>
110+
using EscField2 = EscField<TField, 2>;
99111
using BeSyncField2 = SyncField2<BeField>;
100112
using LeSyncField2 = SyncField2<LeField>;
113+
using BeEscField2 = EscField2<BeField>;
101114
using BeBackInsertSyncField2 = SyncField2<BeBackInsertField>;
102115

103116
template <typename TField, std::size_t TSize, std::size_t TOffset = 0>
@@ -172,7 +185,23 @@ private:
172185
comms::frame::MsgDataLayer<>
173186
>
174187
>,
175-
comms::option::def::FrameLayerSeekField
188+
comms::option::def::FrameLayerSeekField<>
189+
>;
190+
191+
template <typename TSyncField, typename TEscField, typename TSizeField, typename TIdField, typename TMessage>
192+
using SeekFieldWithEscFrame =
193+
comms::frame::SyncPrefixLayer<
194+
TSyncField,
195+
comms::frame::MsgSizeLayer<
196+
TSizeField,
197+
comms::frame::MsgIdLayer<
198+
TIdField,
199+
TMessage,
200+
AllTestMessages<TMessage>,
201+
comms::frame::MsgDataLayer<>
202+
>
203+
>,
204+
comms::option::def::FrameLayerSeekField<TEscField>
176205
>;
177206
};
178207

@@ -406,6 +435,35 @@ void SyncPrefixLayerTestSuite::test9()
406435
BeMsgBase
407436
>;
408437

438+
TestFrame frame;
439+
TestFrame::MsgPtr msg;
440+
auto readIter = comms::readIteratorFor(msg, Buf);
441+
auto es = frame.read(msg, readIter, BufSize);
442+
TS_ASSERT_EQUALS(es, comms::ErrorStatus::Success);
443+
TS_ASSERT(msg);
444+
TS_ASSERT_EQUALS(msg->getId(), MessageType1);
445+
auto& msg1 = dynamic_cast<BeMsg1&>(*msg);
446+
TS_ASSERT_EQUALS(std::get<0>(msg1.fields()).value(), 0x0102);
447+
}
448+
449+
void SyncPrefixLayerTestSuite::test10()
450+
{
451+
static const char Buf[] = {
452+
0x0, 0x1, static_cast<char>(0xde), static_cast<char>(0xad), static_cast<char>(0xab), static_cast<char>(0xcd), // garbage with esc
453+
static_cast<char>(0xab), static_cast<char>(0xcd), 0x0, 0x3, MessageType1, 0x01, 0x02, static_cast<char>(0x3f)
454+
};
455+
456+
static const std::size_t BufSize = std::extent<decltype(Buf)>::value;
457+
458+
using TestFrame =
459+
SeekFieldWithEscFrame<
460+
BeSyncField2,
461+
BeEscField2,
462+
BeSizeField20,
463+
BeIdField1,
464+
BeMsgBase
465+
>;
466+
409467
TestFrame frame;
410468
TestFrame::MsgPtr msg;
411469
auto readIter = comms::readIteratorFor(msg, Buf);

test/SyncSuffixLayer.th

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ private:
9999
AllTestMessages<BeMsgBase>,
100100
comms::frame::MsgDataLayer<>
101101
>,
102-
comms::option::def::FrameLayerSeekField
102+
comms::option::def::FrameLayerSeekField<>
103103
>;
104104
};
105105

0 commit comments

Comments
 (0)