struct-frame 0.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of struct-frame might be problematic. Click here for more details.
- struct-frame/__init__.py +3 -0
- struct-frame/__main__.py +358 -0
- struct-frame/base.py +80 -0
- struct-frame/boilerplate/c/struct_frame.h +103 -0
- struct-frame/boilerplate/c/struct_frame_gen.h +2 -0
- struct-frame/boilerplate/c/struct_frame_parser.h +101 -0
- struct-frame/boilerplate/c/struct_frame_types.h +69 -0
- struct-frame/boilerplate/ts/struct_frame.ts +65 -0
- struct-frame/boilerplate/ts/struct_frame_gen.ts +7 -0
- struct-frame/boilerplate/ts/struct_frame_parser.ts +98 -0
- struct-frame/boilerplate/ts/struct_frame_types.ts +80 -0
- struct-frame/c_gen.py +184 -0
- struct-frame/ts_gen.py +186 -0
- struct_frame-0.0.11.dist-info/METADATA +33 -0
- struct_frame-0.0.11.dist-info/RECORD +17 -0
- struct_frame-0.0.11.dist-info/WHEEL +4 -0
- struct_frame-0.0.11.dist-info/licenses/LICENSE +21 -0
struct-frame/__init__.py
ADDED
struct-frame/__main__.py
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# kate: replace-tabs on; indent-width 4;
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from .c_gen import FileCGen
|
|
6
|
+
from .ts_gen import FileTsGen
|
|
7
|
+
from proto_schema_parser.parser import Parser
|
|
8
|
+
from proto_schema_parser import ast
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
|
|
12
|
+
recErrCurrentField = ""
|
|
13
|
+
recErrCurrentMessage = ""
|
|
14
|
+
|
|
15
|
+
default_types = {
|
|
16
|
+
"uint8": {"size": 1},
|
|
17
|
+
"int8": {"size": 1},
|
|
18
|
+
"uint16": {"size": 2},
|
|
19
|
+
"int16": {"size": 2},
|
|
20
|
+
"uint32": {"size": 4},
|
|
21
|
+
"int32": {"size": 4},
|
|
22
|
+
"bool": {"size": 1},
|
|
23
|
+
"float": {"size": 4},
|
|
24
|
+
"double": {"size": 8}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Enum:
|
|
29
|
+
def __init__(self, package, comments):
|
|
30
|
+
self.name = None
|
|
31
|
+
self.data = {}
|
|
32
|
+
self.size = 1
|
|
33
|
+
self.comments = comments
|
|
34
|
+
self.package = package
|
|
35
|
+
self.isEnum = True
|
|
36
|
+
|
|
37
|
+
def parse(self, enum):
|
|
38
|
+
self.name = enum.name
|
|
39
|
+
comments = []
|
|
40
|
+
for e in enum.elements:
|
|
41
|
+
if type(e) == ast.Comment:
|
|
42
|
+
comments.append(e.text)
|
|
43
|
+
else:
|
|
44
|
+
if e.name in self.data:
|
|
45
|
+
print(f"Enum Field Redclaration")
|
|
46
|
+
return False
|
|
47
|
+
self.data[e.name] = (e.number, comments)
|
|
48
|
+
comments = []
|
|
49
|
+
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
def validate(self, currentPackage, packages):
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
def __str__(self):
|
|
56
|
+
output = ""
|
|
57
|
+
for c in self.comments:
|
|
58
|
+
output = output + c + "\n"
|
|
59
|
+
|
|
60
|
+
output = output + f"Enum: {self.name}\n"
|
|
61
|
+
|
|
62
|
+
for key, value in self.data.items():
|
|
63
|
+
output = output + f"Key: {key}, Value: {value}" + "\n"
|
|
64
|
+
return output
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Field:
|
|
68
|
+
def __init__(self, package, comments):
|
|
69
|
+
self.name = None
|
|
70
|
+
self.fieldType = None
|
|
71
|
+
self.isDefaultType = False
|
|
72
|
+
self.size = 0
|
|
73
|
+
self.validated = False
|
|
74
|
+
self.comments = comments
|
|
75
|
+
self.package = package
|
|
76
|
+
self.isEnum = False
|
|
77
|
+
|
|
78
|
+
def parse(self, field):
|
|
79
|
+
self.name = field.name
|
|
80
|
+
self.fieldType = field.type
|
|
81
|
+
if self.fieldType in default_types:
|
|
82
|
+
self.isDefaultType = True
|
|
83
|
+
self.size = default_types[self.fieldType]["size"]
|
|
84
|
+
self.validated = True
|
|
85
|
+
return True
|
|
86
|
+
|
|
87
|
+
def validate(self, currentPackage, packages):
|
|
88
|
+
|
|
89
|
+
global recErrCurrentField
|
|
90
|
+
recErrCurrentField = self.name
|
|
91
|
+
if not self.validated:
|
|
92
|
+
ret = currentPackage.findFieldType(self.fieldType)
|
|
93
|
+
|
|
94
|
+
if ret:
|
|
95
|
+
if ret.validate(currentPackage, packages):
|
|
96
|
+
self.isEnum = ret.isEnum
|
|
97
|
+
self.validate = True
|
|
98
|
+
self.size = ret.size
|
|
99
|
+
else:
|
|
100
|
+
print(
|
|
101
|
+
f"Failed to validate Field: {self.name} of Type: {self.fieldType} in Package: {currentPackage.name}")
|
|
102
|
+
return False
|
|
103
|
+
else:
|
|
104
|
+
print(
|
|
105
|
+
f"Failed to find Field: {self.name} of Type: {self.fieldType} in Package: {currentPackage.name}")
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
def __str__(self):
|
|
111
|
+
output = ""
|
|
112
|
+
for c in self.comments:
|
|
113
|
+
output = output + c + "\n"
|
|
114
|
+
output = output + \
|
|
115
|
+
f"Field: {self.name}, Type:{self.fieldType}, Size:{self.size}"
|
|
116
|
+
return output
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Message:
|
|
120
|
+
def __init__(self, package, comments):
|
|
121
|
+
self.id = None
|
|
122
|
+
self.size = 0
|
|
123
|
+
self.name = None
|
|
124
|
+
self.fields = {}
|
|
125
|
+
self.validated = False
|
|
126
|
+
self.comments = comments
|
|
127
|
+
self.package = package
|
|
128
|
+
self.isEnum = False
|
|
129
|
+
|
|
130
|
+
def parse(self, msg):
|
|
131
|
+
self.name = msg.name
|
|
132
|
+
comments = []
|
|
133
|
+
for e in msg.elements:
|
|
134
|
+
if type(e) == ast.Option:
|
|
135
|
+
if e.name == "msgid":
|
|
136
|
+
if self.id:
|
|
137
|
+
raise Exception(f"Redefinition of msg_id for {e.name}")
|
|
138
|
+
self.id = e.value
|
|
139
|
+
elif type(e) == ast.Comment:
|
|
140
|
+
comments.append(e.text)
|
|
141
|
+
elif type(e) == ast.Field:
|
|
142
|
+
if e.name in self.fields:
|
|
143
|
+
print(f"Field Redclaration")
|
|
144
|
+
return False
|
|
145
|
+
self.fields[e.name] = Field(self.package, comments)
|
|
146
|
+
comments = []
|
|
147
|
+
if not self.fields[e.name].parse(e):
|
|
148
|
+
return False
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
def validate(self, currentPackage, packages):
|
|
152
|
+
if self.validated:
|
|
153
|
+
return True
|
|
154
|
+
|
|
155
|
+
global recErrCurrentMessage
|
|
156
|
+
recErrCurrentMessage = self.name
|
|
157
|
+
for key, value in self.fields.items():
|
|
158
|
+
if not value.validate(currentPackage, packages):
|
|
159
|
+
print(
|
|
160
|
+
f"Failed To validate Field: {key}, in Message {self.name}\n")
|
|
161
|
+
return False
|
|
162
|
+
self.size = self.size + value.size
|
|
163
|
+
|
|
164
|
+
self.validated = True
|
|
165
|
+
return True
|
|
166
|
+
|
|
167
|
+
def __str__(self):
|
|
168
|
+
output = ""
|
|
169
|
+
for c in self.comments:
|
|
170
|
+
output = output + c + "\n"
|
|
171
|
+
output = output + \
|
|
172
|
+
f"Message: {self.name}, Size: {self.size}, ID: {self.id}\n"
|
|
173
|
+
|
|
174
|
+
for key, value in self.fields.items():
|
|
175
|
+
output = output + value.__str__() + "\n"
|
|
176
|
+
return output
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class Package:
|
|
180
|
+
def __init__(self, name):
|
|
181
|
+
self.name = name
|
|
182
|
+
self.enums = {}
|
|
183
|
+
self.messages = {}
|
|
184
|
+
|
|
185
|
+
def addEnum(self, enum, comments):
|
|
186
|
+
self.comments = comments
|
|
187
|
+
if enum.name in self.enums:
|
|
188
|
+
print(f"Enum Redclaration")
|
|
189
|
+
return False
|
|
190
|
+
self.enums[enum.name] = Enum(self.name, comments)
|
|
191
|
+
return self.enums[enum.name].parse(enum)
|
|
192
|
+
|
|
193
|
+
def addMessage(self, message, comments):
|
|
194
|
+
if message.name in self.messages:
|
|
195
|
+
print(f"Message Redclaration")
|
|
196
|
+
return False
|
|
197
|
+
self.messages[message.name] = Message(self.name, comments)
|
|
198
|
+
return self.messages[message.name].parse(message)
|
|
199
|
+
|
|
200
|
+
def validatePackage(self, allPackages):
|
|
201
|
+
names = []
|
|
202
|
+
for key, value in self.enums.items():
|
|
203
|
+
if value.name in names:
|
|
204
|
+
print(
|
|
205
|
+
f"Name collision with Enum and Message: {value.name} in Packaage {self.name}")
|
|
206
|
+
return False
|
|
207
|
+
names.append(value.name)
|
|
208
|
+
for key, value in self.messages.items():
|
|
209
|
+
if value.name in names:
|
|
210
|
+
print(
|
|
211
|
+
f"Name collision with Enum and Message: {value.name} in Packaage {self.name}")
|
|
212
|
+
return False
|
|
213
|
+
names.append(value.name)
|
|
214
|
+
|
|
215
|
+
for key, value in self.messages.items():
|
|
216
|
+
if not value.validate(self, allPackages):
|
|
217
|
+
print(
|
|
218
|
+
f"Failed To validate Message: {key}, in Package {self.name}\n")
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
return True
|
|
222
|
+
|
|
223
|
+
def findFieldType(self, name):
|
|
224
|
+
for key, value in self.enums.items():
|
|
225
|
+
if value.name == name:
|
|
226
|
+
return value
|
|
227
|
+
|
|
228
|
+
for key, value in self.messages.items():
|
|
229
|
+
if value.name == name:
|
|
230
|
+
return value
|
|
231
|
+
|
|
232
|
+
def sortedMessages(self):
|
|
233
|
+
# Need to sort messages to ensure no out of order dependencies.
|
|
234
|
+
return self.messages
|
|
235
|
+
|
|
236
|
+
def __str__(self):
|
|
237
|
+
output = "Package: " + self.name + "\n"
|
|
238
|
+
for key, value in self.enums.items():
|
|
239
|
+
output = output + value.__str__() + "\n"
|
|
240
|
+
for key, value in self.messages.items():
|
|
241
|
+
output = output + value.__str__() + "\n"
|
|
242
|
+
return output
|
|
243
|
+
|
|
244
|
+
packages = {}
|
|
245
|
+
processed_file = []
|
|
246
|
+
required_file = []
|
|
247
|
+
|
|
248
|
+
parser = argparse.ArgumentParser(
|
|
249
|
+
prog='ProgramName',
|
|
250
|
+
description='What the program does',
|
|
251
|
+
epilog='Text at the bottom of help')
|
|
252
|
+
|
|
253
|
+
parser.add_argument('filename') # positional argument
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def parseFile(filename):
|
|
257
|
+
processed_file.append(filename)
|
|
258
|
+
with open(filename, "r") as f:
|
|
259
|
+
result = Parser().parse(f.read())
|
|
260
|
+
|
|
261
|
+
foundPackage = False
|
|
262
|
+
package_name = ""
|
|
263
|
+
comments = []
|
|
264
|
+
|
|
265
|
+
for e in result.file_elements:
|
|
266
|
+
if (type(e) == ast.Package):
|
|
267
|
+
if foundPackage:
|
|
268
|
+
print(
|
|
269
|
+
f"Multiple Package declaration found in file {filename} - {package_name}")
|
|
270
|
+
return False
|
|
271
|
+
foundPackage = True
|
|
272
|
+
package_name = e.name
|
|
273
|
+
if package_name not in packages:
|
|
274
|
+
packages[package_name] = Package(package_name)
|
|
275
|
+
packages
|
|
276
|
+
|
|
277
|
+
elif (type(e) == ast.Enum):
|
|
278
|
+
if not packages[package_name].addEnum(e, comments):
|
|
279
|
+
print(
|
|
280
|
+
f"Enum Error in Package: {package_name} FileName: {filename} EnumName: {e.name}")
|
|
281
|
+
return False
|
|
282
|
+
comments = []
|
|
283
|
+
|
|
284
|
+
elif (type(e) == ast.Message):
|
|
285
|
+
if not packages[package_name].addMessage(e, comments):
|
|
286
|
+
print(
|
|
287
|
+
f"Message Error in Package: {package_name} FileName: {filename} MessageName: {e.name}")
|
|
288
|
+
return False
|
|
289
|
+
comments = []
|
|
290
|
+
|
|
291
|
+
elif (type(e) == ast.Comment):
|
|
292
|
+
comments.append(e.text)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def validatePackages():
|
|
296
|
+
for key, value in packages.items():
|
|
297
|
+
if not value.validatePackage(packages):
|
|
298
|
+
print(f"Failed To Validate Package: {key}")
|
|
299
|
+
return False
|
|
300
|
+
|
|
301
|
+
return True
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def printPackages():
|
|
305
|
+
for key, value in packages.items():
|
|
306
|
+
print(value)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def generateCFileStrings(path):
|
|
310
|
+
out = {}
|
|
311
|
+
for key, value in packages.items():
|
|
312
|
+
name = path + value.name + ".sf.h"
|
|
313
|
+
data = ''.join(FileCGen.generate(value))
|
|
314
|
+
out[name] = data
|
|
315
|
+
|
|
316
|
+
return out
|
|
317
|
+
|
|
318
|
+
def generateTsFileStrings(path):
|
|
319
|
+
out = {}
|
|
320
|
+
for key, value in packages.items():
|
|
321
|
+
name = path + value.name + ".sf.ts"
|
|
322
|
+
data = ''.join(FileTsGen.generate(value))
|
|
323
|
+
out[name] = data
|
|
324
|
+
|
|
325
|
+
return out
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
import os
|
|
329
|
+
|
|
330
|
+
def main():
|
|
331
|
+
args = parser.parse_args()
|
|
332
|
+
parseFile(args.filename)
|
|
333
|
+
|
|
334
|
+
try:
|
|
335
|
+
validatePackages()
|
|
336
|
+
except RecursionError as err:
|
|
337
|
+
print(
|
|
338
|
+
f'Recursion Error. Messages most likely have a cyclical dependancy. Check Message: {recErrCurrentMessage} and Field: {recErrCurrentField}')
|
|
339
|
+
|
|
340
|
+
cpath = "c/"
|
|
341
|
+
files = generateCFileStrings(cpath)
|
|
342
|
+
|
|
343
|
+
tspath ="ts/"
|
|
344
|
+
files.update(generateTsFileStrings(tspath))
|
|
345
|
+
|
|
346
|
+
for filename, filedata in files.items():
|
|
347
|
+
dirname = os.path.dirname(filename)
|
|
348
|
+
if dirname and not os.path.exists(dirname):
|
|
349
|
+
os.makedirs(dirname)
|
|
350
|
+
|
|
351
|
+
with open(filename , 'w', encoding='utf-8') as f:
|
|
352
|
+
f.write(filedata)
|
|
353
|
+
|
|
354
|
+
#printPackages()
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
if __name__ == '__main__':
|
|
358
|
+
main()
|
struct-frame/base.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
version = "0.0.1"
|
|
5
|
+
|
|
6
|
+
class NamingStyle:
|
|
7
|
+
def enum_name(self, name):
|
|
8
|
+
return "_%s" % (name)
|
|
9
|
+
|
|
10
|
+
def struct_name(self, name):
|
|
11
|
+
return "_%s" % (name)
|
|
12
|
+
|
|
13
|
+
def union_name(self, name):
|
|
14
|
+
return "_%s" % (name)
|
|
15
|
+
|
|
16
|
+
def type_name(self, name):
|
|
17
|
+
return "%s" % (name)
|
|
18
|
+
|
|
19
|
+
def define_name(self, name):
|
|
20
|
+
return "%s" % (name)
|
|
21
|
+
|
|
22
|
+
def var_name(self, name):
|
|
23
|
+
return "%s" % (name)
|
|
24
|
+
|
|
25
|
+
def enum_entry(self, name):
|
|
26
|
+
return "%s" % (name)
|
|
27
|
+
|
|
28
|
+
def func_name(self, name):
|
|
29
|
+
return "%s" % (name)
|
|
30
|
+
|
|
31
|
+
def bytes_type(self, struct_name, name):
|
|
32
|
+
return "%s_%s_t" % (struct_name, name)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NamingStyleC(NamingStyle):
|
|
36
|
+
def enum_name(self, name):
|
|
37
|
+
return self.underscore(name)
|
|
38
|
+
|
|
39
|
+
def struct_name(self, name):
|
|
40
|
+
return self.underscore(name)
|
|
41
|
+
|
|
42
|
+
def union_name(self, name):
|
|
43
|
+
return self.underscore(name)
|
|
44
|
+
|
|
45
|
+
def type_name(self, name):
|
|
46
|
+
return "%s_t" % self.underscore(name)
|
|
47
|
+
|
|
48
|
+
def define_name(self, name):
|
|
49
|
+
return self.underscore(name).upper()
|
|
50
|
+
|
|
51
|
+
def var_name(self, name):
|
|
52
|
+
return self.underscore(name)
|
|
53
|
+
|
|
54
|
+
def enum_entry(self, name):
|
|
55
|
+
return self.underscore(name).upper()
|
|
56
|
+
|
|
57
|
+
def func_name(self, name):
|
|
58
|
+
return self.underscore(name)
|
|
59
|
+
|
|
60
|
+
def bytes_type(self, struct_name, name):
|
|
61
|
+
return "%s_%s_t" % (self.underscore(struct_name), self.underscore(name))
|
|
62
|
+
|
|
63
|
+
def underscore(self, word):
|
|
64
|
+
word = str(word)
|
|
65
|
+
word = re.sub(r"([A-Z]+)([A-Z][a-z])", r'\1_\2', word)
|
|
66
|
+
word = re.sub(r"([a-z\d])([A-Z])", r'\1_\2', word)
|
|
67
|
+
word = word.replace("-", "_")
|
|
68
|
+
return word.lower()
|
|
69
|
+
|
|
70
|
+
def camelCase(st):
|
|
71
|
+
output = ''.join(x for x in st.title() if x.isalnum())
|
|
72
|
+
return output[0].lower() + output[1:]
|
|
73
|
+
|
|
74
|
+
def pascalCase(st):
|
|
75
|
+
return ''.join(x for x in st.title() if x.isalnum())
|
|
76
|
+
|
|
77
|
+
pattern = re.compile(r'(?<!^)(?=[A-Z])')
|
|
78
|
+
|
|
79
|
+
def CamelToSnakeCase(data):
|
|
80
|
+
return pattern.sub('_', data).lower()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "stdbool.h"
|
|
3
|
+
#include "stdint.h"
|
|
4
|
+
#include "string.h"
|
|
5
|
+
#include "struct_frame_types.h"
|
|
6
|
+
|
|
7
|
+
static inline struct checksum_t fletcher_checksum_calculation(uint8_t *buffer, uint8_t data_length)
|
|
8
|
+
{
|
|
9
|
+
checksum_t checksum;
|
|
10
|
+
|
|
11
|
+
for (int i = 0; i < data_length; i++)
|
|
12
|
+
{
|
|
13
|
+
checksum.byte1 += buffer[i];
|
|
14
|
+
checksum.byte2 += checksum.byte1;
|
|
15
|
+
}
|
|
16
|
+
return checksum;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static inline void msg_encode(struct_buffer *buffer, void *msg_buffer, uint8_t msg_id, uint8_t size)
|
|
20
|
+
{
|
|
21
|
+
buffer->data[buffer->size++] = buffer->config.start_byte;
|
|
22
|
+
buffer->crc_start_loc = buffer->size;
|
|
23
|
+
buffer->data[buffer->size++] = msg_id;
|
|
24
|
+
|
|
25
|
+
if (buffer->config.has_len)
|
|
26
|
+
{
|
|
27
|
+
buffer->data[buffer->size++] = size;
|
|
28
|
+
}
|
|
29
|
+
memcpy(buffer->data + buffer->size, (uint8_t *)msg_buffer, size);
|
|
30
|
+
buffer->size += size;
|
|
31
|
+
if (buffer->config.has_crc)
|
|
32
|
+
{
|
|
33
|
+
checksum_t crc = fletcher_checksum_calculation(buffer->data + buffer->crc_start_loc,
|
|
34
|
+
buffer->crc_start_loc - buffer->size);
|
|
35
|
+
buffer->data[buffer->size++] = crc.byte1;
|
|
36
|
+
buffer->data[buffer->size++] = crc.byte2;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static inline void *msg_reserve(struct_buffer *buffer, uint8_t msg_id, uint8_t size)
|
|
41
|
+
{
|
|
42
|
+
if (buffer->in_progress)
|
|
43
|
+
{
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
buffer->in_progress = true;
|
|
47
|
+
buffer->data[buffer->size++] = buffer->config.start_byte;
|
|
48
|
+
|
|
49
|
+
buffer->data[buffer->size++] = msg_id;
|
|
50
|
+
if (buffer->config.has_len)
|
|
51
|
+
{
|
|
52
|
+
buffer->data[buffer->size++] = size;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void *out = &buffer->data[buffer->size];
|
|
56
|
+
buffer->size += size;
|
|
57
|
+
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static inline void msg_finish(struct_buffer *buffer)
|
|
62
|
+
{
|
|
63
|
+
if (buffer->config.has_crc)
|
|
64
|
+
{
|
|
65
|
+
checksum_t crc = fletcher_checksum_calculation(buffer->data + buffer->crc_start_loc,
|
|
66
|
+
buffer->crc_start_loc - buffer->size);
|
|
67
|
+
buffer->data[buffer->size++] = crc.byte1;
|
|
68
|
+
buffer->data[buffer->size++] = crc.byte2;
|
|
69
|
+
}
|
|
70
|
+
buffer->in_progress = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
#define MESSAGE_HELPER(funcname, name, msg_size, msg_id) \
|
|
74
|
+
static inline void funcname##_encode(struct_buffer *buffer, name *name##_obj) \
|
|
75
|
+
{ \
|
|
76
|
+
msg_encode(buffer, name##_obj, msg_id, msg_size); \
|
|
77
|
+
} \
|
|
78
|
+
static inline bool funcname##_reserve(struct_buffer *buffer, name **msg) \
|
|
79
|
+
{ \
|
|
80
|
+
void *ptr = msg_reserve(buffer, msg_id, msg_size); \
|
|
81
|
+
if (ptr) \
|
|
82
|
+
{ \
|
|
83
|
+
*msg = (name *)ptr; \
|
|
84
|
+
return true; \
|
|
85
|
+
} \
|
|
86
|
+
return false; \
|
|
87
|
+
} \
|
|
88
|
+
static inline void funcname##_finish(struct_buffer *buffer) { msg_finish(buffer); } \
|
|
89
|
+
static inline name funcname##_get(struct_buffer *buffer) \
|
|
90
|
+
{ \
|
|
91
|
+
name msg = *(name *)(buffer->data); \
|
|
92
|
+
return msg; \
|
|
93
|
+
} \
|
|
94
|
+
static inline name funcname##_get_from_buffer_result(buffer_parser_result_t result) \
|
|
95
|
+
{ \
|
|
96
|
+
name msg = *(name *)(result.msg_loc); \
|
|
97
|
+
return msg; \
|
|
98
|
+
} \
|
|
99
|
+
static inline name *funcname##_get_ref(struct_buffer *buffer) { return (name *)(buffer->data); } \
|
|
100
|
+
static inline name *funcname##_get_ref_from_buffer_result(buffer_parser_result_t result) \
|
|
101
|
+
{ \
|
|
102
|
+
return (name *)(result.msg_loc); \
|
|
103
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "stdint.h"
|
|
3
|
+
#include "struct_frame_gen.h"
|
|
4
|
+
#include "struct_frame_types.h"
|
|
5
|
+
|
|
6
|
+
// https://github.com/serge-sans-paille/frozen
|
|
7
|
+
|
|
8
|
+
static inline bool parse_default_format_validate(uint8_t *data, msg_id_len_t *msg_id_len) {
|
|
9
|
+
(void)data;
|
|
10
|
+
(void)msg_id_len;
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static inline bool parse_default_format_char_for_len_id(msg_id_len_t *msg_id_len, const uint8_t c) {
|
|
15
|
+
msg_id_len->msg_id = c;
|
|
16
|
+
msg_id_len->len = get_message_length(c);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
parser_functions_t default_parser_functions = {parse_default_format_char_for_len_id,
|
|
21
|
+
parse_default_format_validate};
|
|
22
|
+
|
|
23
|
+
static inline parser_functions_t *parse_char_for_start_byte(const struct_frame_config config,
|
|
24
|
+
const uint8_t c) {
|
|
25
|
+
if (config.start_byte == c) {
|
|
26
|
+
return &default_parser_functions;
|
|
27
|
+
}
|
|
28
|
+
return NULL;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static inline bool parse_char(struct_buffer *pb, uint8_t c) {
|
|
32
|
+
parser_functions_t *parse_func_ptr = NULL;
|
|
33
|
+
switch (pb->state) {
|
|
34
|
+
case LOOKING_FOR_START_BYTE:
|
|
35
|
+
parse_func_ptr = parse_char_for_start_byte(pb->config, c);
|
|
36
|
+
if (parse_func_ptr) {
|
|
37
|
+
pb->config.parser_funcs = parse_func_ptr;
|
|
38
|
+
pb->state = GETTING_LENGTH_MSG_AND_ID;
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
|
|
42
|
+
case GETTING_LENGTH_MSG_AND_ID:
|
|
43
|
+
if (pb->config.parser_funcs->get_msg_id_len(&pb->msg_id_len, c)) {
|
|
44
|
+
pb->state = GETTING_PAYLOAD;
|
|
45
|
+
pb->size = 0;
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
|
|
49
|
+
case GETTING_PAYLOAD:
|
|
50
|
+
pb->data[pb->size++] = c;
|
|
51
|
+
if (pb->size >= pb->msg_id_len.len) {
|
|
52
|
+
pb->state = LOOKING_FOR_START_BYTE;
|
|
53
|
+
return pb->config.parser_funcs->validate_packet(pb->data, &pb->msg_id_len);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
break;
|
|
57
|
+
|
|
58
|
+
default:
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static inline bool parse_buffer(uint8_t *buffer, size_t size, buffer_parser_result_t *parser_result) {
|
|
66
|
+
enum ParserState state = LOOKING_FOR_START_BYTE;
|
|
67
|
+
parser_functions_t *parse_func_ptr;
|
|
68
|
+
for (size_t i = parser_result->r_loc; i < size; i++) {
|
|
69
|
+
switch (state) {
|
|
70
|
+
case LOOKING_FOR_START_BYTE:
|
|
71
|
+
parse_func_ptr = parse_char_for_start_byte(parser_result->config, buffer[i]);
|
|
72
|
+
if (parse_func_ptr) {
|
|
73
|
+
state = GETTING_LENGTH_MSG_AND_ID;
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case GETTING_LENGTH_MSG_AND_ID:
|
|
78
|
+
if (parse_func_ptr->get_msg_id_len(&parser_result->msg_id_len, buffer[i])) {
|
|
79
|
+
state = GETTING_PAYLOAD;
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
|
|
83
|
+
case GETTING_PAYLOAD:
|
|
84
|
+
parser_result->msg_loc = buffer + i;
|
|
85
|
+
parser_result->r_loc = i + parser_result->msg_id_len.len;
|
|
86
|
+
parser_result->found = true;
|
|
87
|
+
if (parse_func_ptr->validate_packet(parser_result->msg_loc, &parser_result->msg_id_len)) {
|
|
88
|
+
parser_result->valid = true;
|
|
89
|
+
return true;
|
|
90
|
+
} else {
|
|
91
|
+
parser_result->valid = false;
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
|
|
96
|
+
default:
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|