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.

@@ -0,0 +1,3 @@
1
+ #from .ast import Field, FieldCardinality, Message, Option
2
+ #from .parser import Parser
3
+ #__all__ = ["Parser", "Message", "Field", "Option", "FieldCardinality"]
@@ -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,2 @@
1
+ #pragma once
2
+ #include "myl_vehicle.sf.h"
@@ -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
+ }