-
Notifications
You must be signed in to change notification settings - Fork 0
/
paker.hpp
325 lines (271 loc) · 11.4 KB
/
paker.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/*
* paker.hpp
* piotr022, sq9p.peter@gmail.com
*/
#pragma once
#include <string.h>
#include <math.h>
namespace Protocol
{
namespace Paker
{
struct TFormatElement
{
const char c8Id;
const unsigned int u32Base;
const char *C8CharcterMap;
};
// compile time format info
template <unsigned int ElmSize, const TFormatElement (&FormatElemets)[ElmSize], const char pattern[]>
class CFormat
{
static constexpr auto PatternLen = strlen(pattern);
using ArrType = const char[PatternLen];
public:
static constexpr auto GetLen() { return PatternLen; }
static constexpr auto GetPattern() { return pattern; }
static constexpr auto GetSeqNrIdx()
{
for (unsigned int i = 0; i < GetLen(); i++)
{
if (pattern[i] == 'S')
return i;
}
return (unsigned int)UINT32_MAX;
}
static constexpr unsigned int GetBase(unsigned int u32Idx)
{
if (u32Idx >= GetLen())
return 0;
return GetBase(pattern[u32Idx]);
}
static constexpr unsigned int GetBase(const char sign)
{
for (const auto &element : FormatElemets)
{
if (element.c8Id == sign)
return element.u32Base;
}
return 1;
}
static constexpr auto GetMaxPermutations()
{
return GetPermutationsRightSide(0);
}
static constexpr auto GetPermutationsRightSide(unsigned int u32Idx)
{
unsigned long long u64Permutations = 1;
for (unsigned int i = u32Idx; i < GetLen(); i++)
{
u64Permutations *= GetBase(i);
}
return u64Permutations;
}
static constexpr auto GetBitSizeFloor()
{
return (unsigned int)floor(log2(GetMaxPermutations()));
}
static constexpr const TFormatElement &GetFormatElement(unsigned int u32FormatIdx)
{
for (const auto &element : FormatElemets)
{
if (element.c8Id == pattern[u32FormatIdx])
return element;
}
return FormatElemets[0];
}
static constexpr auto CustomBaseMap(unsigned int u32FormatIdx, unsigned int u32Val)
{
const auto &PatternElement = GetFormatElement(u32FormatIdx);
if (u32Val >= PatternElement.u32Base || !PatternElement.C8CharcterMap)
return PatternElement.c8Id;
return PatternElement.C8CharcterMap[u32Val];
}
static constexpr unsigned int CustomBaseToDec(unsigned int u32FormatIdx, char c8Input)
{
const auto &PatternElement = GetFormatElement(u32FormatIdx);
if (!PatternElement.C8CharcterMap || PatternElement.c8Id == 'S')
return 0;
for (unsigned int i = 0; i < strlen(PatternElement.C8CharcterMap); i++)
{
if (PatternElement.C8CharcterMap[i] == c8Input)
{
return i;
}
}
return 0;
}
static constexpr auto SequenceNrMap(unsigned char u8SequenceNr)
{
auto const &SequenceFormatElem = GetFormatElement(GetSeqNrIdx());
return SequenceFormatElem.C8CharcterMap[u8SequenceNr % strlen(SequenceFormatElem.C8CharcterMap)];
}
static constexpr char GetPatternCharacter(unsigned int u32Idx)
{
if (u32Idx >= GetLen())
{
return ' ';
}
return pattern[u32Idx];
}
};
template <class FormatT, unsigned int BuffersCnt>
class TEncoder
{
char (&OutBuffors)[BuffersCnt][FormatT::GetLen() + 1];
public:
static constexpr auto MaxSubframes = BuffersCnt;
using Format = FormatT;
template <unsigned int N>
TEncoder(char (&outStrArrs)[BuffersCnt][N]) : OutBuffors(outStrArrs){};
unsigned int EncodeBigEndian(unsigned char *p8Data, unsigned int u32BitSize) // conisering little endian arch
{
unsigned int u32SrcBitIdx = 0;
const auto requeredFrames = (u32BitSize + FormatT::GetBitSizeFloor() - 1) / FormatT::GetBitSizeFloor();
for (unsigned int u32Frame = 0; u32Frame < requeredFrames; u32Frame++)
{
unsigned long long u64Temp = 0;
BitwiseCopy(&u64Temp, 0, p8Data, u32SrcBitIdx, std::min(FormatT::GetBitSizeFloor(), u32BitSize - u32SrcBitIdx));
for (unsigned int u32SymbolIdx = 0; u32SymbolIdx < FormatT::GetLen(); u32SymbolIdx++)
{
if (u32SymbolIdx == FormatT::GetSeqNrIdx())
{
OutBuffors[u32Frame][u32SymbolIdx] = FormatT::SequenceNrMap(u32Frame);
continue;
}
auto const SymbolBase = FormatT::GetBase(u32SymbolIdx);
if (SymbolBase < 2)
{
OutBuffors[u32Frame][u32SymbolIdx] = FormatT::GetPatternCharacter(u32SymbolIdx);
continue;
}
unsigned long long u64CurrentSymbol = u64Temp / FormatT::GetPermutationsRightSide(u32SymbolIdx + 1);
u64CurrentSymbol %= SymbolBase;
OutBuffors[u32Frame][u32SymbolIdx] = FormatT::CustomBaseMap(u32SymbolIdx, u64CurrentSymbol);
}
u32SrcBitIdx += FormatT::GetBitSizeFloor();
}
return requeredFrames;
}
unsigned int DecodeBigEndian(unsigned char u8FramesToDecode, unsigned char *pOutData, unsigned int u32OutBuffLen)
{
// unsigned int
if (u32OutBuffLen * 8 < u8FramesToDecode * FormatT::GetBitSizeFloor())
{
return 0;
}
unsigned int u32OutDataBitIdx = 0;
for (unsigned int u32Frame = 0; u32Frame < u8FramesToDecode; u32Frame++)
{
unsigned long long u64Temp = 0;
for (unsigned int u32SymbolIdx = 0; u32SymbolIdx < FormatT::GetLen(); u32SymbolIdx++)
{
if (u32SymbolIdx == FormatT::GetSeqNrIdx())
continue;
u64Temp += FormatT::CustomBaseToDec(u32SymbolIdx, OutBuffors[u32Frame][u32SymbolIdx]) *
FormatT::GetPermutationsRightSide(u32SymbolIdx + 1);
}
BitwiseCopy(pOutData, u32OutDataBitIdx, (unsigned char *)&u64Temp, 0, FormatT::GetBitSizeFloor());
u32OutDataBitIdx += FormatT::GetBitSizeFloor();
}
return u32OutDataBitIdx;
}
private:
void BitwiseCopy(void *pDest, unsigned int u32DestBitIdx, const unsigned char *pSource, unsigned int u32SourceBitIdx, unsigned int u32BitsToCopy)
{
while (u32BitsToCopy--)
{
unsigned char u8Bit = pSource[u32SourceBitIdx / 8] >> (u32SourceBitIdx % 8);
u8Bit &= 1;
unsigned char *p8Dest = reinterpret_cast<unsigned char *>(pDest);
p8Dest[u32DestBitIdx / 8] &= ~(1 << (u32DestBitIdx % 8));
p8Dest[u32DestBitIdx / 8] |= (u8Bit << (u32DestBitIdx % 8));
u32DestBitIdx++;
u32SourceBitIdx++;
}
}
};
struct TPatternFormats
{
TPatternFormats() = delete;
static constexpr auto DefElmCnt = 8;
static constexpr TFormatElement DefaultFormatElements[DefElmCnt] =
{
{'0', 1, " "}, // nothing
{'S', 1, "0123456789"}, // sequence number
{'x', 26, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"},
{'X', 36, "ABCDEFGHIJKLMNOPRSTQUWXYVZ0123456789"},
{'l', 18, "ABCDEFGHIJKLMNOPQR"},
{'U', 10, "0123456789"},
{'P', 28, "ABCDEFGHIJKLMNOPQRSTUVWXYZab"},
};
static constexpr auto WsprElmCnt = 8;
static constexpr TFormatElement WsprFormatElements[WsprElmCnt] =
{
{'0', 1, " "}, // nothing
{'S', 1, "01Q"}, // sequence number
{'x', 26, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"},
{'X', 36, "ABCDEFGHIJKLMNOPRSTQUWXYVZ0123456789"},
{'l', 18, "ABCDEFGHIJKLMNOPQR"},
{'U', 10, "0123456789"},
{'P', 28, "ABCDEFGHIJKLMNOPQRSTUVWXYZab"},
};
static constexpr auto Jt9ElmCnt = 3;
static constexpr TFormatElement Jt9FormatElements[Jt9ElmCnt] =
{
{'0', 1, " "}, // nothing
{'S', 1, "01Q"}, // sequence number
{'J', 42, "ABCDEFGHIJKLMNOPRSTQUWXYVZ0123456789 +=./?"},
};
};
template <const char pattern[]>
using CFormatWithDefaultElementsT = CFormat<TPatternFormats::DefElmCnt, TPatternFormats::DefaultFormatElements, pattern>;
template <const char pattern[]>
using CWsprFormatT = CFormat<TPatternFormats::WsprElmCnt, TPatternFormats::WsprFormatElements, pattern>;
template <const char pattern[]>
using CJt9Format = CFormat<TPatternFormats::Jt9ElmCnt, TPatternFormats::Jt9FormatElements, pattern>;
template <class CEncoder>
class CPacketFactoryT
{
public:
using Format = typename CEncoder::Format;
char C8Frames[CEncoder::MaxSubframes][Format::GetLen() + 1];
CEncoder Encoder;
unsigned char u8EncodedFrames = 0;
CPacketFactoryT() : Encoder(C8Frames){};
const char *GetPacket(unsigned int u32Idx)
{
if (u32Idx >= CEncoder::MaxSubframes)
return "NOT VALID";
return C8Frames[u32Idx];
}
bool AppendWsFrame(const char *p8WsFrame)
{
auto const SeqIdx = Format::GetSeqNrIdx();
if (strlen(p8WsFrame) != Format::GetLen() ||
p8WsFrame[SeqIdx] < '0' || p8WsFrame[SeqIdx] > '9')
return false;
auto const FrameNr = p8WsFrame[SeqIdx] - '0';
memcpy(C8Frames[FrameNr], p8WsFrame, Format::GetLen());
return true;
}
unsigned int EncodeRaw(unsigned char *p8Data, unsigned int u32BitLen)
{
u8EncodedFrames = Encoder.EncodeBigEndian(p8Data, u32BitLen);
return u8EncodedFrames;
}
unsigned int DecodeFrames(unsigned char u8FramesToDecode, unsigned char *pOutData, unsigned int u32OutBuffLen)
{
return Encoder.DecodeBigEndian(u8FramesToDecode, pOutData, u32OutBuffLen);
}
};
template <const char C8Format[], template<auto> class CFromatT, unsigned int MaxElements>
using CPacketFactory = CPacketFactoryT<TEncoder<CFromatT<C8Format>, MaxElements>>;
static constexpr char Ft4FromatString[] = "CQ 4NSxxxxxxx";
using CFT4PacketFactory = CPacketFactory<Ft4FromatString,CFormatWithDefaultElementsT, 8>;
static constexpr char WsprFormatString[] = "CQ SUUxxx llUU P";
using CWsprPacketFactory = CPacketFactory<WsprFormatString, CWsprFormatT, 8>;
static constexpr char Jt9FormatString[] = "JJJJJJJJJJJJJ";
using CJt9PacketFactory = CPacketFactory<Jt9FormatString, CJt9Format, 8>;
}
}