struct-frame 0.0.24__py3-none-any.whl → 0.0.27__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 +2 -1
- struct_frame/c_gen.py +3 -3
- struct_frame/generate.py +17 -5
- struct_frame/gql_gen.py +145 -0
- struct_frame/py_gen.py +22 -23
- struct_frame-0.0.27.dist-info/METADATA +62 -0
- struct_frame-0.0.27.dist-info/RECORD +12 -0
- struct_frame/boilerplate/c/struct_frame.h +0 -103
- struct_frame/boilerplate/c/struct_frame_cpp.h +0 -41
- struct_frame/boilerplate/c/struct_frame_gen.h +0 -1
- struct_frame/boilerplate/c/struct_frame_parser.h +0 -101
- struct_frame/boilerplate/c/struct_frame_types.h +0 -67
- struct_frame/boilerplate/py/struct_frame_parser.py +0 -118
- struct_frame/boilerplate/ts/struct_frame.ts +0 -65
- struct_frame/boilerplate/ts/struct_frame_gen.ts +0 -7
- struct_frame/boilerplate/ts/struct_frame_parser.ts +0 -98
- struct_frame/boilerplate/ts/struct_frame_types.ts +0 -80
- struct_frame-0.0.24.dist-info/METADATA +0 -29
- struct_frame-0.0.24.dist-info/RECORD +0 -21
- {struct_frame-0.0.24.dist-info → struct_frame-0.0.27.dist-info}/WHEEL +0 -0
- {struct_frame-0.0.24.dist-info → struct_frame-0.0.27.dist-info}/licenses/LICENSE +0 -0
struct_frame/__init__.py
CHANGED
|
@@ -3,8 +3,9 @@ from .base import version, NamingStyleC, CamelToSnakeCase, pascalCase
|
|
|
3
3
|
from .c_gen import FileCGen
|
|
4
4
|
from .ts_gen import FileTsGen
|
|
5
5
|
from .py_gen import FilePyGen
|
|
6
|
+
from .gql_gen import FileGqlGen
|
|
6
7
|
|
|
7
8
|
from .generate import main
|
|
8
9
|
|
|
9
|
-
__all__ = ["main", "FileCGen", "FileTsGen", "FilePyGen", "version",
|
|
10
|
+
__all__ = ["main", "FileCGen", "FileTsGen", "FilePyGen", "FileGqlGen", "version",
|
|
10
11
|
"NamingStyleC", "CamelToSnakeCase", "pascalCase"]
|
struct_frame/c_gen.py
CHANGED
|
@@ -178,12 +178,12 @@ class FileCGen():
|
|
|
178
178
|
# yield '\n'
|
|
179
179
|
|
|
180
180
|
if package.messages:
|
|
181
|
-
yield '
|
|
181
|
+
yield 'bool get_message_length(size_t msg_id, size_t* size){\n switch (msg_id)\n {\n'
|
|
182
182
|
for key, msg in package.sortedMessages().items():
|
|
183
183
|
name = '%s_%s' % (CamelToSnakeCase(
|
|
184
184
|
msg.package).upper(), CamelToSnakeCase(msg.name).upper())
|
|
185
185
|
if msg.id:
|
|
186
|
-
yield ' case %s_MSG_ID:
|
|
186
|
+
yield ' case %s_MSG_ID: *size = %s_MAX_SIZE; return true;\n' % (name, name)
|
|
187
187
|
|
|
188
|
-
yield ' default: break;\n } return
|
|
188
|
+
yield ' default: break;\n } return false;\n}'
|
|
189
189
|
yield '\n'
|
struct_frame/generate.py
CHANGED
|
@@ -7,6 +7,7 @@ import shutil
|
|
|
7
7
|
from struct_frame import FileCGen
|
|
8
8
|
from struct_frame import FileTsGen
|
|
9
9
|
from struct_frame import FilePyGen
|
|
10
|
+
from struct_frame import FileGqlGen
|
|
10
11
|
from proto_schema_parser.parser import Parser
|
|
11
12
|
from proto_schema_parser import ast
|
|
12
13
|
|
|
@@ -260,9 +261,12 @@ parser.add_argument('--debug', action='store_true')
|
|
|
260
261
|
parser.add_argument('--build_c', action='store_true')
|
|
261
262
|
parser.add_argument('--build_ts', action='store_true')
|
|
262
263
|
parser.add_argument('--build_py', action='store_true')
|
|
263
|
-
parser.add_argument('--c_path', nargs=1, type=str, default=['c/'])
|
|
264
|
-
parser.add_argument('--ts_path', nargs=1, type=str, default=['ts/'])
|
|
265
|
-
parser.add_argument('--py_path', nargs=1, type=str, default=['py/'])
|
|
264
|
+
parser.add_argument('--c_path', nargs=1, type=str, default=['generated/c/'])
|
|
265
|
+
parser.add_argument('--ts_path', nargs=1, type=str, default=['generated/ts/'])
|
|
266
|
+
parser.add_argument('--py_path', nargs=1, type=str, default=['generated/py/'])
|
|
267
|
+
parser.add_argument('--build_gql', action='store_true')
|
|
268
|
+
parser.add_argument('--gql_path', nargs=1, type=str,
|
|
269
|
+
default=['generated/gql/'])
|
|
266
270
|
|
|
267
271
|
|
|
268
272
|
def parseFile(filename):
|
|
@@ -340,7 +344,7 @@ def generateTsFileStrings(path):
|
|
|
340
344
|
def generatePyFileStrings(path):
|
|
341
345
|
out = {}
|
|
342
346
|
for key, value in packages.items():
|
|
343
|
-
name = os.path.join(path, value.name + ".
|
|
347
|
+
name = os.path.join(path, value.name + "_sf.py")
|
|
344
348
|
data = ''.join(FilePyGen.generate(value))
|
|
345
349
|
out[name] = data
|
|
346
350
|
return out
|
|
@@ -350,7 +354,7 @@ def main():
|
|
|
350
354
|
args = parser.parse_args()
|
|
351
355
|
parseFile(args.filename)
|
|
352
356
|
|
|
353
|
-
if (not args.build_c and not args.build_ts and not args.build_py):
|
|
357
|
+
if (not args.build_c and not args.build_ts and not args.build_py and not args.build_gql):
|
|
354
358
|
print("Select at least one build argument")
|
|
355
359
|
return
|
|
356
360
|
|
|
@@ -370,6 +374,12 @@ def main():
|
|
|
370
374
|
if (args.build_py):
|
|
371
375
|
files.update(generatePyFileStrings(args.py_path[0]))
|
|
372
376
|
|
|
377
|
+
if (args.build_gql):
|
|
378
|
+
for key, value in packages.items():
|
|
379
|
+
name = os.path.join(args.gql_path[0], value.name + '.graphql')
|
|
380
|
+
data = ''.join(FileGqlGen.generate(value))
|
|
381
|
+
files[name] = data
|
|
382
|
+
|
|
373
383
|
for filename, filedata in files.items():
|
|
374
384
|
dirname = os.path.dirname(filename)
|
|
375
385
|
if dirname and not os.path.exists(dirname):
|
|
@@ -392,6 +402,8 @@ def main():
|
|
|
392
402
|
shutil.copytree(os.path.join(dir_path, "boilerplate/py"),
|
|
393
403
|
args.py_path[0], dirs_exist_ok=True)
|
|
394
404
|
|
|
405
|
+
# No boilerplate for GraphQL currently
|
|
406
|
+
|
|
395
407
|
if args.debug:
|
|
396
408
|
printPackages()
|
|
397
409
|
print("Struct Frame successfully completed")
|
struct_frame/gql_gen.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Simple GraphQL schema generator for struct-frame
|
|
3
|
+
|
|
4
|
+
from struct_frame import version, pascalCase, CamelToSnakeCase
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
# Mapping from proto primitive types to GraphQL scalar types
|
|
8
|
+
gql_types = {
|
|
9
|
+
"uint8": "Int",
|
|
10
|
+
"int8": "Int",
|
|
11
|
+
"uint16": "Int",
|
|
12
|
+
"int16": "Int",
|
|
13
|
+
"uint32": "Int",
|
|
14
|
+
"int32": "Int",
|
|
15
|
+
"uint64": "Int", # Could be custom scalar if needed
|
|
16
|
+
"int64": "Int", # Could be custom scalar if needed
|
|
17
|
+
"bool": "Boolean",
|
|
18
|
+
"float": "Float",
|
|
19
|
+
"double": "Float",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _gql_enum_value_name(name: str) -> str:
|
|
24
|
+
# If already in ALL_CAPS (possibly with underscores) keep as is
|
|
25
|
+
if name.replace('_', '').isupper():
|
|
26
|
+
return name
|
|
27
|
+
return CamelToSnakeCase(name).upper()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _clean_comment_line(c: str) -> str:
|
|
31
|
+
c = c.strip()
|
|
32
|
+
if c.startswith('#'):
|
|
33
|
+
c = c[1:].strip()
|
|
34
|
+
# Remove leading // once or twice
|
|
35
|
+
if c.startswith('//'):
|
|
36
|
+
c = c[2:].strip()
|
|
37
|
+
# If parser already kept leading markers inside line, remove repeated
|
|
38
|
+
if c.startswith('//'):
|
|
39
|
+
c = c[2:].strip()
|
|
40
|
+
return c
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _triple_quote_block(lines):
|
|
44
|
+
cleaned = [_clean_comment_line(l) for l in lines if _clean_comment_line(l)]
|
|
45
|
+
if not cleaned:
|
|
46
|
+
return None
|
|
47
|
+
return '"""\n' + '\n'.join(cleaned) + '\n"""'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _single_quote_line(lines):
|
|
51
|
+
cleaned = [_clean_comment_line(l) for l in lines if _clean_comment_line(l)]
|
|
52
|
+
if not cleaned:
|
|
53
|
+
return None
|
|
54
|
+
# Join multi-line into one sentence for single-line description
|
|
55
|
+
return '"' + ' '.join(cleaned) + '"'
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class EnumGqlGen:
|
|
59
|
+
@staticmethod
|
|
60
|
+
def generate(enum):
|
|
61
|
+
lines = []
|
|
62
|
+
if enum.comments:
|
|
63
|
+
desc = _triple_quote_block(enum.comments)
|
|
64
|
+
if desc:
|
|
65
|
+
lines.append(desc)
|
|
66
|
+
enum_name = f"{pascalCase(enum.package)}{enum.name}"
|
|
67
|
+
lines.append(f"enum {enum_name} {{")
|
|
68
|
+
for key, value in enum.data.items():
|
|
69
|
+
if value[1]:
|
|
70
|
+
desc = _single_quote_line(value[1])
|
|
71
|
+
if desc:
|
|
72
|
+
lines.append(f" {desc}")
|
|
73
|
+
lines.append(f" {_gql_enum_value_name(key)}")
|
|
74
|
+
lines.append("}\n")
|
|
75
|
+
return '\n'.join(lines)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class FieldGqlGen:
|
|
79
|
+
@staticmethod
|
|
80
|
+
def type_name(field):
|
|
81
|
+
t = field.fieldType
|
|
82
|
+
if t in gql_types:
|
|
83
|
+
return gql_types[t]
|
|
84
|
+
return f"{pascalCase(field.package)}{t}"
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def generate(field):
|
|
88
|
+
lines = []
|
|
89
|
+
if field.comments:
|
|
90
|
+
desc = _single_quote_line(field.comments)
|
|
91
|
+
if desc:
|
|
92
|
+
lines.append(f" {desc}")
|
|
93
|
+
lines.append(f" {field.name}: {FieldGqlGen.type_name(field)}")
|
|
94
|
+
return '\n'.join(lines)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class MessageGqlGen:
|
|
98
|
+
@staticmethod
|
|
99
|
+
def generate(msg):
|
|
100
|
+
lines = []
|
|
101
|
+
if msg.comments:
|
|
102
|
+
desc = _triple_quote_block(msg.comments)
|
|
103
|
+
if desc:
|
|
104
|
+
lines.append(desc)
|
|
105
|
+
type_name = f"{pascalCase(msg.package)}{msg.name}"
|
|
106
|
+
lines.append(f"type {type_name} {{")
|
|
107
|
+
if not msg.fields:
|
|
108
|
+
lines.append(" _empty: Boolean")
|
|
109
|
+
else:
|
|
110
|
+
for key, f in msg.fields.items():
|
|
111
|
+
lines.append(FieldGqlGen.generate(f))
|
|
112
|
+
lines.append("}\n")
|
|
113
|
+
return '\n'.join(lines)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class FileGqlGen:
|
|
117
|
+
@staticmethod
|
|
118
|
+
def generate(package):
|
|
119
|
+
# Multiline triple-quoted header block
|
|
120
|
+
yield f"# Automatically generated GraphQL schema\n# Generated by struct-frame {version} at {time.asctime()}\n\n"
|
|
121
|
+
|
|
122
|
+
first_block = True
|
|
123
|
+
# Enums
|
|
124
|
+
for _, enum in package.enums.items():
|
|
125
|
+
if not first_block:
|
|
126
|
+
yield '\n'
|
|
127
|
+
first_block = False
|
|
128
|
+
yield EnumGqlGen.generate(enum).rstrip() + '\n'
|
|
129
|
+
|
|
130
|
+
# Messages (object types)
|
|
131
|
+
for _, msg in package.sortedMessages().items():
|
|
132
|
+
if not first_block:
|
|
133
|
+
yield '\n'
|
|
134
|
+
first_block = False
|
|
135
|
+
yield MessageGqlGen.generate(msg).rstrip() + '\n'
|
|
136
|
+
|
|
137
|
+
# Root Query type
|
|
138
|
+
if package.messages:
|
|
139
|
+
if not first_block:
|
|
140
|
+
yield '\n'
|
|
141
|
+
yield 'type Query {\n'
|
|
142
|
+
for _, msg in package.sortedMessages().items():
|
|
143
|
+
type_name = f"{pascalCase(msg.package)}{msg.name}"
|
|
144
|
+
yield f" {msg.name}: {type_name}\n"
|
|
145
|
+
yield '}\n'
|
struct_frame/py_gen.py
CHANGED
|
@@ -88,33 +88,32 @@ class MessagePyGen():
|
|
|
88
88
|
structName = '%s%s' % (pascalCase(msg.package), msg.name)
|
|
89
89
|
result += 'class %s(Structured):\n' % structName
|
|
90
90
|
result += ' msg_size = %s\n' % msg.size
|
|
91
|
-
if msg.id:
|
|
91
|
+
if msg.id != None:
|
|
92
92
|
result += ' msg_id = %s\n' % msg.id
|
|
93
93
|
|
|
94
|
-
size = 1
|
|
95
|
-
if not msg.fields:
|
|
96
|
-
# Empty structs are not allowed in C standard.
|
|
97
|
-
# Therefore add a dummy field if an empty message occurs.
|
|
98
|
-
result += ' dummy_field: pad'
|
|
99
|
-
else:
|
|
100
|
-
size = msg.size
|
|
101
|
-
|
|
102
94
|
result += '\n'.join([FieldPyGen.generate(f)
|
|
103
95
|
for key, f in msg.fields.items()])
|
|
104
96
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
97
|
+
result += '\n\n def __str__(self):\n'
|
|
98
|
+
result += f' out = "{msg.name} Msg, ID {msg.id}, Size {msg.size} \\n"\n'
|
|
99
|
+
for key, f in msg.fields.items():
|
|
100
|
+
result += f' out += f"{key} = '
|
|
101
|
+
result += '{self.' + key + '}\\n"\n'
|
|
102
|
+
result += f' out += "\\n"\n'
|
|
103
|
+
result += f' return out'
|
|
104
|
+
|
|
105
|
+
result += '\n\n def to_dict(self, include_name = True, include_id = True):\n'
|
|
106
|
+
result += f' out = {{'
|
|
107
|
+
for key, f in msg.fields.items():
|
|
108
|
+
result += f' "{key}" : self.{key}{"" if f.isDefaultType | f.isEnum else ".to_dict(False, False)" }, '
|
|
109
|
+
result += f'}}\n'
|
|
110
|
+
result += f' if include_name:\n'
|
|
111
|
+
result += f' out["name"] = "{msg.name}"\n'
|
|
112
|
+
result += f' if include_id:\n'
|
|
113
|
+
result += f' out["msg_id"] = "{msg.id}"\n'
|
|
114
|
+
result += f' return out\n'
|
|
115
|
+
|
|
116
|
+
return result
|
|
118
117
|
|
|
119
118
|
@staticmethod
|
|
120
119
|
def get_initializer(msg, null_init):
|
|
@@ -153,7 +152,7 @@ class FilePyGen():
|
|
|
153
152
|
|
|
154
153
|
yield '%s_definitions = {\n' % package.name
|
|
155
154
|
for key, msg in package.sortedMessages().items():
|
|
156
|
-
if msg.id:
|
|
155
|
+
if msg.id != None:
|
|
157
156
|
structName = '%s%s' % (pascalCase(msg.package), msg.name)
|
|
158
157
|
yield ' %s: %s,\n' % (msg.id, structName)
|
|
159
158
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: struct-frame
|
|
3
|
+
Version: 0.0.27
|
|
4
|
+
Summary: A framework for serializing data with headers
|
|
5
|
+
Project-URL: Homepage, https://github.com/mylonics/struct-frame
|
|
6
|
+
Project-URL: Issues, https://github.com/mylonics/struct-frame/issues
|
|
7
|
+
Author-email: Rijesh Augustine <rijesh@mylonics.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Requires-Dist: proto-schema-parser>=1.4.5
|
|
14
|
+
Requires-Dist: structured-classes>=3.1.0
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Struct Frame
|
|
19
|
+
|
|
20
|
+
A framework for serializing data with headers
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### Python Usage
|
|
25
|
+
```bash
|
|
26
|
+
# Install dependencies
|
|
27
|
+
pip install -e .
|
|
28
|
+
|
|
29
|
+
# Generate code from proto file
|
|
30
|
+
python src/main.py examples/myl_vehicle.proto --build_c --build_ts --build_py
|
|
31
|
+
|
|
32
|
+
# Generated files will be in the generated/ directory
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### TypeScript Example
|
|
36
|
+
```bash
|
|
37
|
+
# Install TypeScript dependencies
|
|
38
|
+
npm i -D typescript typed-struct @types/node
|
|
39
|
+
|
|
40
|
+
# Generate TypeScript code first
|
|
41
|
+
python src/main.py examples/myl_vehicle.proto --build_ts
|
|
42
|
+
|
|
43
|
+
# Compile and run the example
|
|
44
|
+
npx tsc examples/index.ts --outDir generated/
|
|
45
|
+
node generated/examples/index.js
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### C Example
|
|
49
|
+
```bash
|
|
50
|
+
# Generate C code first
|
|
51
|
+
python src/main.py examples/myl_vehicle.proto --build_c
|
|
52
|
+
|
|
53
|
+
# Compile the C example
|
|
54
|
+
gcc examples/main.c -I generated/c -o main
|
|
55
|
+
./main
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Project Structure
|
|
59
|
+
|
|
60
|
+
- `src/` - Source code for the struct-frame library
|
|
61
|
+
- `examples/` - Example usage and demo files
|
|
62
|
+
- `generated/` - Generated output files (ignored by git)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
struct_frame/__init__.py,sha256=m9hfIbcgCYvt-fIeYrJRQyk6I7rq35jSdZIhrMmZntg,374
|
|
2
|
+
struct_frame/__main__.py,sha256=tIybnBeFHvwiwVhodVOSnxhne5AX_80mtXBx4rneSB4,143
|
|
3
|
+
struct_frame/base.py,sha256=1Z_0vMkwz0X8r2hIVLv5yuhwwD929LwNMzVKBqFxxac,2012
|
|
4
|
+
struct_frame/c_gen.py,sha256=RFzEx0EuMoxBwdRi3O1NZGJ4iw3c3h7g8rRU3zD2ubU,5997
|
|
5
|
+
struct_frame/generate.py,sha256=rfz7d0w37UWs0qlylOhYgD3k0GVmBoaZAGWQp_HUmHc,13131
|
|
6
|
+
struct_frame/gql_gen.py,sha256=6-zaocD3qgPQyovjAihxl3DJZ9OHXM225VvO5KQmtkI,4488
|
|
7
|
+
struct_frame/py_gen.py,sha256=7kvMsWPxAyLzTQg_BRj3g-yICH-6ilIGxMABEQdLayQ,4980
|
|
8
|
+
struct_frame/ts_gen.py,sha256=qdJgAMxL2lV_WmGZErjHpgukYHNNpKpECarXdfmngEI,6266
|
|
9
|
+
struct_frame-0.0.27.dist-info/METADATA,sha256=LwhsBrTZ0SQOMrMbHgWguP3d796SfASF8QwTe_y9cjU,1578
|
|
10
|
+
struct_frame-0.0.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
+
struct_frame-0.0.27.dist-info/licenses/LICENSE,sha256=UjbLtGfcHCIqJg9UzEVGoNW8fyX4Ah9ZbsuAmJ_vhmk,1094
|
|
12
|
+
struct_frame-0.0.27.dist-info/RECORD,,
|
|
@@ -1,103 +0,0 @@
|
|
|
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
|
-
checksum_t checksum;
|
|
9
|
-
|
|
10
|
-
for (int i = 0; i < data_length; i++) {
|
|
11
|
-
checksum.byte1 += buffer[i];
|
|
12
|
-
checksum.byte2 += checksum.byte1;
|
|
13
|
-
}
|
|
14
|
-
return checksum;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
static inline bool msg_encode(struct_buffer *buffer, void *msg_buffer, uint8_t msg_id, uint8_t size) {
|
|
18
|
-
if (buffer->in_progress) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
buffer->in_progress = true;
|
|
22
|
-
|
|
23
|
-
buffer->data[buffer->size++] = buffer->config.start_byte;
|
|
24
|
-
buffer->crc_start_loc = buffer->size;
|
|
25
|
-
buffer->data[buffer->size++] = msg_id;
|
|
26
|
-
|
|
27
|
-
if (buffer->config.has_len) {
|
|
28
|
-
buffer->data[buffer->size++] = size;
|
|
29
|
-
}
|
|
30
|
-
memcpy(buffer->data + buffer->size, (uint8_t *)msg_buffer, size);
|
|
31
|
-
buffer->size += size;
|
|
32
|
-
if (buffer->config.has_crc) {
|
|
33
|
-
checksum_t crc =
|
|
34
|
-
fletcher_checksum_calculation(buffer->data + buffer->crc_start_loc, buffer->crc_start_loc - buffer->size);
|
|
35
|
-
buffer->data[buffer->size++] = crc.byte1;
|
|
36
|
-
buffer->data[buffer->size++] = crc.byte2;
|
|
37
|
-
}
|
|
38
|
-
buffer->in_progress = false;
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
static inline void *msg_reserve(struct_buffer *buffer, uint8_t msg_id, uint8_t size) {
|
|
43
|
-
if (buffer->in_progress) {
|
|
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
|
-
buffer->data[buffer->size++] = size;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
void *out = &buffer->data[buffer->size];
|
|
55
|
-
buffer->size += size;
|
|
56
|
-
|
|
57
|
-
return out;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
static inline bool msg_finish(struct_buffer *buffer) {
|
|
61
|
-
if (buffer->in_progress == false) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
if (buffer->config.has_crc) {
|
|
65
|
-
checksum_t crc =
|
|
66
|
-
fletcher_checksum_calculation(buffer->data + buffer->crc_start_loc, 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
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
#define MESSAGE_HELPER(funcname, name, msg_size, msg_id) \
|
|
75
|
-
static inline bool funcname##_encode(struct_buffer *buffer, name *name##_obj) { \
|
|
76
|
-
return msg_encode(buffer, name##_obj, msg_id, msg_size); \
|
|
77
|
-
} \
|
|
78
|
-
static inline bool funcname##_reserve(struct_buffer *buffer, name **msg) { \
|
|
79
|
-
void *ptr = msg_reserve(buffer, msg_id, msg_size); \
|
|
80
|
-
if (ptr) { \
|
|
81
|
-
*msg = (name *)ptr; \
|
|
82
|
-
return true; \
|
|
83
|
-
} \
|
|
84
|
-
return false; \
|
|
85
|
-
} \
|
|
86
|
-
static inline bool funcname##_finish(struct_buffer *buffer) { return msg_finish(buffer); } \
|
|
87
|
-
static inline name funcname##_get(struct_buffer *buffer) { \
|
|
88
|
-
name msg = *(name *)(buffer->data); \
|
|
89
|
-
return msg; \
|
|
90
|
-
} \
|
|
91
|
-
static inline name funcname##_get(uint8_t *buffer) { \
|
|
92
|
-
name msg = *(name *)(buffer); \
|
|
93
|
-
return msg; \
|
|
94
|
-
} \
|
|
95
|
-
static inline name funcname##_get_from_buffer_result(buffer_parser_result_t result) { \
|
|
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(uint8_t *buffer) { return (name *)(buffer); } \
|
|
101
|
-
static inline name *funcname##_get_ref_from_buffer_result(buffer_parser_result_t result) { \
|
|
102
|
-
return (name *)(result.msg_loc); \
|
|
103
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "struct_frame_parser.h"
|
|
4
|
-
#include "struct_frame_types.h"
|
|
5
|
-
|
|
6
|
-
class StructFrameDevice : public struct_buffer {
|
|
7
|
-
public:
|
|
8
|
-
StructFrameDevice(struct_frame_config config)
|
|
9
|
-
: struct_buffer{config, nullptr, 0, 0, false, 0, LOOKING_FOR_START_BYTE, 0, {false, 0, 0}},
|
|
10
|
-
parser_result_{config, false, 0, 0, false, {0, 0}} {}
|
|
11
|
-
|
|
12
|
-
void RunRx() {
|
|
13
|
-
uint8_t *buffer;
|
|
14
|
-
size_t buffer_size;
|
|
15
|
-
GetArray(buffer, buffer_size);
|
|
16
|
-
if (buffer && buffer_size) {
|
|
17
|
-
while (!parser_result_.finished) {
|
|
18
|
-
if (parse_buffer(buffer, buffer_size, &parser_result_)) {
|
|
19
|
-
if (parser_result_.valid) {
|
|
20
|
-
HandleResult();
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
void RunTx() { PutArray(struct_buffer::data, struct_buffer::max_size, struct_buffer::size); }
|
|
28
|
-
|
|
29
|
-
protected:
|
|
30
|
-
void Init() { PutArray(struct_buffer::data, struct_buffer::max_size, 0); }
|
|
31
|
-
|
|
32
|
-
// Put Array must accept the full buffer of data and returns a pointer to either a new buffer or the same buffer
|
|
33
|
-
// that is free
|
|
34
|
-
virtual void PutArray(uint8_t *&buffer, size_t &max_length, size_t length) = 0;
|
|
35
|
-
|
|
36
|
-
// Get array, a pointer to an array and refernce to the array length is pased and mutated by this function
|
|
37
|
-
virtual void GetArray(uint8_t *&buffer, size_t &length) = 0;
|
|
38
|
-
|
|
39
|
-
virtual void HandleResult() = 0;
|
|
40
|
-
buffer_parser_result_t parser_result_;
|
|
41
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
@@ -1,101 +0,0 @@
|
|
|
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, parse_default_format_validate};
|
|
21
|
-
|
|
22
|
-
static inline parser_functions_t *parse_char_for_start_byte(const struct_frame_config config, const uint8_t c) {
|
|
23
|
-
if (config.start_byte == c) {
|
|
24
|
-
return &default_parser_functions;
|
|
25
|
-
}
|
|
26
|
-
return NULL;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
static inline bool parse_char(struct_buffer *pb, uint8_t c) {
|
|
30
|
-
parser_functions_t *parse_func_ptr = NULL;
|
|
31
|
-
switch (pb->state) {
|
|
32
|
-
case LOOKING_FOR_START_BYTE:
|
|
33
|
-
parse_func_ptr = parse_char_for_start_byte(pb->config, c);
|
|
34
|
-
if (parse_func_ptr) {
|
|
35
|
-
pb->config.parser_funcs = parse_func_ptr;
|
|
36
|
-
pb->state = GETTING_LENGTH_MSG_AND_ID;
|
|
37
|
-
}
|
|
38
|
-
break;
|
|
39
|
-
|
|
40
|
-
case GETTING_LENGTH_MSG_AND_ID:
|
|
41
|
-
if (pb->config.parser_funcs->get_msg_id_len(&pb->msg_id_len, c)) {
|
|
42
|
-
pb->state = GETTING_PAYLOAD;
|
|
43
|
-
pb->size = 0;
|
|
44
|
-
}
|
|
45
|
-
break;
|
|
46
|
-
|
|
47
|
-
case GETTING_PAYLOAD:
|
|
48
|
-
pb->data[pb->size++] = c;
|
|
49
|
-
if (pb->size >= pb->msg_id_len.len) {
|
|
50
|
-
pb->state = LOOKING_FOR_START_BYTE;
|
|
51
|
-
return pb->config.parser_funcs->validate_packet(pb->data, &pb->msg_id_len);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
break;
|
|
55
|
-
|
|
56
|
-
default:
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static inline bool parse_buffer(uint8_t *buffer, size_t size, buffer_parser_result_t *parser_result) {
|
|
64
|
-
enum ParserState state = LOOKING_FOR_START_BYTE;
|
|
65
|
-
parser_functions_t *parse_func_ptr;
|
|
66
|
-
parser_result->finished = false;
|
|
67
|
-
for (size_t i = parser_result->r_loc; i < size; i++) {
|
|
68
|
-
switch (state) {
|
|
69
|
-
case LOOKING_FOR_START_BYTE:
|
|
70
|
-
parse_func_ptr = parse_char_for_start_byte(parser_result->config, buffer[i]);
|
|
71
|
-
if (parse_func_ptr) {
|
|
72
|
-
state = GETTING_LENGTH_MSG_AND_ID;
|
|
73
|
-
}
|
|
74
|
-
break;
|
|
75
|
-
|
|
76
|
-
case GETTING_LENGTH_MSG_AND_ID:
|
|
77
|
-
if (parse_func_ptr->get_msg_id_len(&parser_result->msg_id_len, buffer[i])) {
|
|
78
|
-
state = GETTING_PAYLOAD;
|
|
79
|
-
}
|
|
80
|
-
break;
|
|
81
|
-
|
|
82
|
-
case GETTING_PAYLOAD:
|
|
83
|
-
parser_result->msg_loc = buffer + i;
|
|
84
|
-
parser_result->r_loc = i + parser_result->msg_id_len.len;
|
|
85
|
-
if (parse_func_ptr->validate_packet(parser_result->msg_loc, &parser_result->msg_id_len)) {
|
|
86
|
-
parser_result->valid = true;
|
|
87
|
-
return true;
|
|
88
|
-
} else {
|
|
89
|
-
parser_result->valid = false;
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
break;
|
|
93
|
-
|
|
94
|
-
default:
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
parser_result->finished = true;
|
|
99
|
-
parser_result->r_loc = 0;
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "stdbool.h"
|
|
4
|
-
#include "stdint.h"
|
|
5
|
-
|
|
6
|
-
typedef struct _msg_id_len_t {
|
|
7
|
-
bool valid;
|
|
8
|
-
uint8_t len;
|
|
9
|
-
uint8_t msg_id;
|
|
10
|
-
} msg_id_len_t;
|
|
11
|
-
|
|
12
|
-
typedef struct _parser_functions_t {
|
|
13
|
-
bool (*get_msg_id_len)(msg_id_len_t *, uint8_t);
|
|
14
|
-
bool (*validate_packet)(uint8_t *, msg_id_len_t *);
|
|
15
|
-
} parser_functions_t;
|
|
16
|
-
|
|
17
|
-
typedef struct _struct_frame_config {
|
|
18
|
-
uint8_t has_crc;
|
|
19
|
-
uint8_t has_len;
|
|
20
|
-
uint8_t start_byte;
|
|
21
|
-
parser_functions_t *parser_funcs;
|
|
22
|
-
} struct_frame_config;
|
|
23
|
-
|
|
24
|
-
enum ParserState { LOOKING_FOR_START_BYTE = 0, GETTING_LENGTH_MSG_AND_ID = 1, GETTING_PAYLOAD = 2 };
|
|
25
|
-
|
|
26
|
-
typedef struct _struct_frame_buffer {
|
|
27
|
-
// Used for framing and parsing
|
|
28
|
-
struct_frame_config config;
|
|
29
|
-
uint8_t *data;
|
|
30
|
-
size_t max_size;
|
|
31
|
-
size_t size;
|
|
32
|
-
bool in_progress;
|
|
33
|
-
|
|
34
|
-
// Used for framing
|
|
35
|
-
size_t crc_start_loc;
|
|
36
|
-
|
|
37
|
-
// Used for parsing
|
|
38
|
-
enum ParserState state;
|
|
39
|
-
size_t payload_len;
|
|
40
|
-
msg_id_len_t msg_id_len;
|
|
41
|
-
|
|
42
|
-
} struct_buffer;
|
|
43
|
-
|
|
44
|
-
typedef struct _buffer_parser_result_t {
|
|
45
|
-
struct_frame_config config;
|
|
46
|
-
bool valid;
|
|
47
|
-
uint8_t *msg_loc;
|
|
48
|
-
size_t r_loc;
|
|
49
|
-
bool finished;
|
|
50
|
-
msg_id_len_t msg_id_len;
|
|
51
|
-
} buffer_parser_result_t;
|
|
52
|
-
|
|
53
|
-
// https://github.com/serge-sans-paille/frozen
|
|
54
|
-
// https://www.npmjs.com/package/typed-struct
|
|
55
|
-
|
|
56
|
-
#define default_parser {0, 0, 0x90}
|
|
57
|
-
|
|
58
|
-
#define zero_initialized_parser_result {default_parser, false, 0, 0, false, {0, 0}}
|
|
59
|
-
|
|
60
|
-
#define CREATE_DEFAULT_STRUCT_BUFFER(name, size) \
|
|
61
|
-
uint8_t name##_buffer[size]; \
|
|
62
|
-
struct_buffer name = {default_parser, name##_buffer, size, 0, false, 0, LOOKING_FOR_START_BYTE, 0, {false, 0, 0}};
|
|
63
|
-
|
|
64
|
-
typedef struct checksum_t {
|
|
65
|
-
uint8_t byte1;
|
|
66
|
-
uint8_t byte2;
|
|
67
|
-
} checksum_t;
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from enum import Enum
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def fletcher_checksum_calculation(buffer, start=0, end=None):
|
|
6
|
-
if end == None:
|
|
7
|
-
end = buffer.length
|
|
8
|
-
|
|
9
|
-
byte1 = 0
|
|
10
|
-
byte2 = 2
|
|
11
|
-
|
|
12
|
-
for x in range(start, end):
|
|
13
|
-
byte1 += buffer[x]
|
|
14
|
-
byte2 += byte1
|
|
15
|
-
|
|
16
|
-
return [byte1, byte2]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class BasicPacket:
|
|
20
|
-
start_byte = None
|
|
21
|
-
header_length = 0
|
|
22
|
-
footer_length = 0
|
|
23
|
-
|
|
24
|
-
desired_packet_length = 0
|
|
25
|
-
packet = []
|
|
26
|
-
|
|
27
|
-
def __init__(self, start_byte, header_length, footer_length):
|
|
28
|
-
self.start_byte = start_byte
|
|
29
|
-
self.header_length = header_length
|
|
30
|
-
self.footer_length = footer_length
|
|
31
|
-
|
|
32
|
-
def add_header_byte(self, byte, clear):
|
|
33
|
-
if clear:
|
|
34
|
-
self.packet.clear()
|
|
35
|
-
self.packet.push(byte)
|
|
36
|
-
return len(self.packet) == self.header_length
|
|
37
|
-
|
|
38
|
-
def add_packet_byte(self, byte):
|
|
39
|
-
self.packet.push(byte)
|
|
40
|
-
return len(self.packet) == self.desired_packet_length
|
|
41
|
-
|
|
42
|
-
def get_msg_id(self):
|
|
43
|
-
return self.packet[1]
|
|
44
|
-
|
|
45
|
-
def get_full_packet_length(self, msg_length):
|
|
46
|
-
self.desired_packet_length = self.header_length + self.footer_length + msg_length
|
|
47
|
-
return self.desired_packet_length
|
|
48
|
-
|
|
49
|
-
def validate_packet(self):
|
|
50
|
-
checksum = fletcher_checksum_calculation(
|
|
51
|
-
self.packet, self.header_length, self.desired_packet_length - self.footer_length)
|
|
52
|
-
return checksum[0] == self.packet[-2] and checksum[1] == self.packet[-1]
|
|
53
|
-
|
|
54
|
-
def get_msg_buffer(self):
|
|
55
|
-
return self.packet[self.header_length:self.desired_packet_length - self.footer_length]
|
|
56
|
-
|
|
57
|
-
def encode(self, data, msg_id):
|
|
58
|
-
output = []
|
|
59
|
-
output.push(self.start_byte)
|
|
60
|
-
output.push(msg_id)
|
|
61
|
-
output.push(data)
|
|
62
|
-
checksum = fletcher_checksum_calculation(data)
|
|
63
|
-
|
|
64
|
-
output.push(checksum[0])
|
|
65
|
-
output.push(checksum[1])
|
|
66
|
-
return output
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class ParserState(Enum):
|
|
70
|
-
LOOKING_FOR_START_BYTE = 0
|
|
71
|
-
GETTING_HEADER = 1
|
|
72
|
-
GETTING_PACKET = 2
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class FrameParser:
|
|
76
|
-
state = ParserState.LOOKING_FOR_START_BYTE
|
|
77
|
-
buffer = []
|
|
78
|
-
parser = None
|
|
79
|
-
msg_definitions = None
|
|
80
|
-
msg_id_loc = None
|
|
81
|
-
msg_type = None
|
|
82
|
-
|
|
83
|
-
def __init__(self, parsers, msg_definitions):
|
|
84
|
-
self.parsers = parsers
|
|
85
|
-
self.msg_definitions = msg_definitions
|
|
86
|
-
|
|
87
|
-
def parse_char(self, c):
|
|
88
|
-
if state == ParserState.LOOKING_FOR_START_BYTE:
|
|
89
|
-
self.parser = self.parsers[c]
|
|
90
|
-
if self.parser:
|
|
91
|
-
if self.parser.add_header_byte(c, True):
|
|
92
|
-
state = ParserState.GETTING_PACKET
|
|
93
|
-
else:
|
|
94
|
-
state = ParserState.GETTING_HEADER
|
|
95
|
-
|
|
96
|
-
elif state == ParserState.GETTING_HEADER:
|
|
97
|
-
if self.parser.add_header_byte(c):
|
|
98
|
-
msg_id = self.parser.get_msg_id()
|
|
99
|
-
self.msg_type = self.msg_definitions[msg_id]
|
|
100
|
-
if self.msg_type:
|
|
101
|
-
self.parser.get_full_packet_length(self.msg_type.msg_size)
|
|
102
|
-
state = ParserState.GETTING_PACKET
|
|
103
|
-
else:
|
|
104
|
-
state = ParserState.LOOKING_FOR_START_BYTE
|
|
105
|
-
|
|
106
|
-
elif state == ParserState.GETTING_PACKET:
|
|
107
|
-
if self.parser.add_packet_byte(c):
|
|
108
|
-
state = ParserState.LOOKING_FOR_START_BYTE
|
|
109
|
-
if self.parser.validatePackage:
|
|
110
|
-
return self.msg_type.create_unpack(self.parser.get_msg_buffer())
|
|
111
|
-
|
|
112
|
-
return False
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def TestFunction():
|
|
116
|
-
parsers = {BasicPacket.start_byte, BasicPacket()}
|
|
117
|
-
frameParser = FrameParser(parsers)
|
|
118
|
-
frameParser.parse_char
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { Struct } from 'typed-struct';
|
|
2
|
-
import * as sf_types from './struct_frame_types';
|
|
3
|
-
|
|
4
|
-
function fletcher_checksum_calculation(buffer: Uint8Array, data_length: number): sf_types.checksum_t {
|
|
5
|
-
const checksum: sf_types.checksum_t = { byte1: 0, byte2: 0 };
|
|
6
|
-
|
|
7
|
-
for (let i = 0; i < data_length; i++) {
|
|
8
|
-
checksum.byte1 += buffer[i];
|
|
9
|
-
checksum.byte2 += checksum.byte1;
|
|
10
|
-
}
|
|
11
|
-
return checksum;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function msg_encode(buffer: sf_types.struct_frame_buffer, msg: any, msgid: number) {
|
|
15
|
-
buffer.data[buffer.size++] = buffer.config.start_byte;
|
|
16
|
-
buffer.crc_start_loc = buffer.size;
|
|
17
|
-
buffer.data[buffer.size++] = msgid;
|
|
18
|
-
|
|
19
|
-
if (buffer.config.has_len) {
|
|
20
|
-
buffer.data[buffer.size++] = msg.getSize();
|
|
21
|
-
}
|
|
22
|
-
const rawData = Struct.raw(msg);
|
|
23
|
-
for (let i = 0; i < rawData.length; i++) {
|
|
24
|
-
buffer.data[buffer.size++] = rawData[i]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (buffer.config.has_crc) {
|
|
28
|
-
const crc = fletcher_checksum_calculation(buffer.data.slice(buffer.crc_start_loc), buffer.crc_start_loc + rawData.length);
|
|
29
|
-
buffer.data[buffer.size++] = crc.byte1;
|
|
30
|
-
buffer.data[buffer.size++] = crc.byte2;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function msg_reserve(buffer: sf_types.struct_frame_buffer, msg_id: number, msg_size: number) {
|
|
35
|
-
throw new Error('Function Unimplemented');
|
|
36
|
-
|
|
37
|
-
if (buffer.in_progress) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
buffer.in_progress = true;
|
|
41
|
-
buffer.data[buffer.size++] = buffer.config.start_byte;
|
|
42
|
-
|
|
43
|
-
buffer.data[buffer.size++] = msg_id;
|
|
44
|
-
if (buffer.config.has_len) {
|
|
45
|
-
buffer.data[buffer.size++] = msg_size;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const ret = Buffer.from(buffer.data, buffer.size, msg_size);
|
|
49
|
-
buffer.size += msg_size;
|
|
50
|
-
return ret;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
export function msg_finish(buffer: sf_types.struct_frame_buffer) {
|
|
56
|
-
throw new Error('Function Unimplemented');
|
|
57
|
-
|
|
58
|
-
if (buffer.config.has_crc) {
|
|
59
|
-
const crc = fletcher_checksum_calculation(buffer.data.slice(buffer.crc_start_loc), buffer.crc_start_loc - buffer.size);
|
|
60
|
-
buffer.data[buffer.size++] = crc.byte1;
|
|
61
|
-
buffer.data[buffer.size++] = crc.byte2;
|
|
62
|
-
buffer.size += 2
|
|
63
|
-
}
|
|
64
|
-
buffer.in_progress = false;
|
|
65
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { get_message_length } from './struct_frame_gen';
|
|
2
|
-
import * as sf_types from './struct_frame_types';
|
|
3
|
-
|
|
4
|
-
function parse_default_format_validate(buffer: Uint8Array, msg_id_len: sf_types.msg_id_len_t): boolean {
|
|
5
|
-
return true;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function parse_default_format_char_for_len_id(c: number, msg_id_len: sf_types.msg_id_len_t): boolean {
|
|
9
|
-
msg_id_len.msg_id = c;
|
|
10
|
-
msg_id_len.len = get_message_length(c);
|
|
11
|
-
return true;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const default_parser_functions: sf_types.parser_functions_t = { get_msg_id_len: parse_default_format_char_for_len_id, validate_packet: parse_default_format_validate };
|
|
15
|
-
|
|
16
|
-
function parse_char_for_start_byte(config: sf_types.struct_frame_config, c: number): sf_types.parser_functions_t | undefined {
|
|
17
|
-
if (config.start_byte == c) {
|
|
18
|
-
return default_parser_functions;
|
|
19
|
-
}
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function parse_char(pb: sf_types.struct_frame_buffer, c: number): boolean {
|
|
24
|
-
let parse_func_ptr: sf_types.parser_functions_t | undefined = undefined;
|
|
25
|
-
switch (pb.state) {
|
|
26
|
-
case sf_types.ParserState.LOOKING_FOR_START_BYTE:
|
|
27
|
-
parse_func_ptr = parse_char_for_start_byte(pb.config, c);
|
|
28
|
-
if (parse_func_ptr) {
|
|
29
|
-
pb.config.parser_funcs = parse_func_ptr;
|
|
30
|
-
pb.state = sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID;
|
|
31
|
-
}
|
|
32
|
-
break;
|
|
33
|
-
|
|
34
|
-
case sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID:
|
|
35
|
-
if (pb.config.parser_funcs && pb.config.parser_funcs.get_msg_id_len(c, pb.msg_id_len)) {
|
|
36
|
-
pb.state = sf_types.ParserState.GETTING_PAYLOAD;
|
|
37
|
-
pb.size = 0;
|
|
38
|
-
}
|
|
39
|
-
break;
|
|
40
|
-
|
|
41
|
-
case sf_types.ParserState.GETTING_PAYLOAD:
|
|
42
|
-
pb.data[pb.size] = c;
|
|
43
|
-
pb.size++;
|
|
44
|
-
if (pb.size >= pb.msg_id_len.len) {
|
|
45
|
-
pb.msg_data = Buffer.from(pb.data, 0, pb.size)
|
|
46
|
-
pb.state = sf_types.ParserState.LOOKING_FOR_START_BYTE;
|
|
47
|
-
if (pb.config.parser_funcs) {
|
|
48
|
-
return pb.config.parser_funcs.validate_packet(pb.data, pb.msg_id_len);
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
break;
|
|
53
|
-
|
|
54
|
-
default:
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function parse_buffer(buffer: Uint8Array, size: number, parser_result: sf_types.buffer_parser_result_t): boolean {
|
|
62
|
-
let state: sf_types.ParserState = sf_types.ParserState.LOOKING_FOR_START_BYTE;
|
|
63
|
-
let parse_func_ptr: sf_types.parser_functions_t | undefined;
|
|
64
|
-
for (let i = parser_result.r_loc; i < size; i++) {
|
|
65
|
-
switch (state) {
|
|
66
|
-
case sf_types.ParserState.LOOKING_FOR_START_BYTE:
|
|
67
|
-
parse_func_ptr = parse_char_for_start_byte(parser_result.config, buffer[i]);
|
|
68
|
-
if (parse_func_ptr) {
|
|
69
|
-
state = sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID;
|
|
70
|
-
}
|
|
71
|
-
break;
|
|
72
|
-
|
|
73
|
-
case sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID:
|
|
74
|
-
if (parse_func_ptr && parse_func_ptr.get_msg_id_len(buffer[i], parser_result.msg_id_len)) {
|
|
75
|
-
state = sf_types.ParserState.GETTING_PAYLOAD;
|
|
76
|
-
}
|
|
77
|
-
break;
|
|
78
|
-
|
|
79
|
-
case sf_types.ParserState.GETTING_PAYLOAD:
|
|
80
|
-
parser_result.msg_data = Buffer.from(buffer, i, (i + parser_result.msg_id_len.len));
|
|
81
|
-
parser_result.r_loc = i + parser_result.msg_id_len.len;
|
|
82
|
-
parser_result.found = true;
|
|
83
|
-
if (parse_func_ptr && parse_func_ptr.validate_packet(parser_result.msg_data, parser_result.msg_id_len)) {
|
|
84
|
-
parser_result.valid = true;
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
parser_result.valid = false;
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
break;
|
|
92
|
-
|
|
93
|
-
default:
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export class msg_id_len_t {
|
|
3
|
-
valid = false;
|
|
4
|
-
len = 0;
|
|
5
|
-
msg_id = 0;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type GetMsgIdLenType = (c: number, msg_id_len: msg_id_len_t) => boolean;
|
|
9
|
-
export type ValidatePacketType = (buffer: Uint8Array, msg_id_len: msg_id_len_t) => boolean;
|
|
10
|
-
|
|
11
|
-
export interface parser_functions_t {
|
|
12
|
-
get_msg_id_len: GetMsgIdLenType;
|
|
13
|
-
validate_packet: ValidatePacketType;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface struct_frame_config {
|
|
17
|
-
has_crc: number;
|
|
18
|
-
has_len: number;
|
|
19
|
-
start_byte: number;
|
|
20
|
-
parser_funcs?: parser_functions_t;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export enum ParserState {
|
|
24
|
-
LOOKING_FOR_START_BYTE = 0,
|
|
25
|
-
GETTING_LENGTH_MSG_AND_ID = 1,
|
|
26
|
-
GETTING_PAYLOAD = 2
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const basic_frame_config: struct_frame_config = { has_crc: 0, has_len: 0, start_byte: 0x90 };
|
|
30
|
-
|
|
31
|
-
export class struct_frame_buffer {
|
|
32
|
-
// Used for framing and parsing
|
|
33
|
-
config: struct_frame_config = basic_frame_config;
|
|
34
|
-
data: Uint8Array;
|
|
35
|
-
size = 0;
|
|
36
|
-
in_progress = false;
|
|
37
|
-
|
|
38
|
-
// Used for framing
|
|
39
|
-
crc_start_loc = 0;
|
|
40
|
-
|
|
41
|
-
// Used for parsing
|
|
42
|
-
state: ParserState = ParserState.LOOKING_FOR_START_BYTE;
|
|
43
|
-
payload_len = 0;
|
|
44
|
-
msg_id_len: msg_id_len_t = new msg_id_len_t();
|
|
45
|
-
msg_data: Buffer = Buffer.allocUnsafe(0);
|
|
46
|
-
|
|
47
|
-
constructor(public max_size: number, buffer?: Uint8Array) {
|
|
48
|
-
if (buffer) {
|
|
49
|
-
this.data = buffer;
|
|
50
|
-
} else {
|
|
51
|
-
this.data = new Uint8Array(max_size);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export class buffer_parser_result_t {
|
|
57
|
-
config: struct_frame_config = basic_frame_config;
|
|
58
|
-
found = false;
|
|
59
|
-
valid = false;
|
|
60
|
-
msg_data: Buffer = Buffer.allocUnsafe(0);
|
|
61
|
-
r_loc = 0;
|
|
62
|
-
finished = false;
|
|
63
|
-
msg_id_len: msg_id_len_t = new msg_id_len_t();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// https://github.com/serge-sans-paille/frozen
|
|
67
|
-
// https://www.npmjs.com/package/typed-struct
|
|
68
|
-
|
|
69
|
-
//#define default_parser { 0, 0, 0x90 }
|
|
70
|
-
//
|
|
71
|
-
//#define zero_initialized_parser_result { default_parser, false, false, 0, 0, false, { 0, 0} };
|
|
72
|
-
//
|
|
73
|
-
//#define CREATE_DEFAULT_STRUCT_BUFFER(name, size) \
|
|
74
|
-
// uint8_t name##_buffer[size]; \
|
|
75
|
-
// struct_buffer name = { default_parser, name##_buffer, size, 0, 0, false, 0, 0, 0, 0, NULL }
|
|
76
|
-
|
|
77
|
-
export interface checksum_t {
|
|
78
|
-
byte1: number;
|
|
79
|
-
byte2: number;
|
|
80
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: struct-frame
|
|
3
|
-
Version: 0.0.24
|
|
4
|
-
Summary: A framework for serializing data with headers
|
|
5
|
-
Project-URL: Homepage, https://github.com/mylonics/struct-frame
|
|
6
|
-
Project-URL: Issues, https://github.com/mylonics/struct-frame/issues
|
|
7
|
-
Author-email: Rijesh Augustine <rijesh@mylonics.com>
|
|
8
|
-
License-Expression: MIT
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Requires-Python: >=3.8
|
|
13
|
-
Requires-Dist: proto-schema-parser>=1.4.5
|
|
14
|
-
Requires-Dist: structured-classes>=3.1.0
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
TS install
|
|
20
|
-
|
|
21
|
-
npm i -D typescript typed-struct @types/node
|
|
22
|
-
npx tsc --init
|
|
23
|
-
npx tsc index.ts
|
|
24
|
-
node index.js
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
npx tsc --project tsconfig.json; node index.js
|
|
28
|
-
|
|
29
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
struct_frame/__init__.py,sha256=6v6MeHXVPlCn-sXE23fbGHqz8VA_xqCab8yeJ61-Njo,327
|
|
2
|
-
struct_frame/__main__.py,sha256=tIybnBeFHvwiwVhodVOSnxhne5AX_80mtXBx4rneSB4,143
|
|
3
|
-
struct_frame/base.py,sha256=1Z_0vMkwz0X8r2hIVLv5yuhwwD929LwNMzVKBqFxxac,2012
|
|
4
|
-
struct_frame/c_gen.py,sha256=dQw52Zgec38O471KaHuYkRyehcxfjmSOpvhppExgB1c,5969
|
|
5
|
-
struct_frame/generate.py,sha256=vAPTCLikB_DIy_mopLRWovZqDlOe8Y61Z6gcQi9AMdI,12598
|
|
6
|
-
struct_frame/py_gen.py,sha256=6sdZEPBUteNUh2lv2OWLdJlj2Q_r-WipQX7kF6BHAvo,4811
|
|
7
|
-
struct_frame/ts_gen.py,sha256=qdJgAMxL2lV_WmGZErjHpgukYHNNpKpECarXdfmngEI,6266
|
|
8
|
-
struct_frame/boilerplate/c/struct_frame.h,sha256=sVJtzKsA5H6irH_dTdbVmiL0A74cG8AhzO37xSlANzo,5074
|
|
9
|
-
struct_frame/boilerplate/c/struct_frame_cpp.h,sha256=S6KEgeW78TGVeGGRuTseTXwkMNtzFT-n7faRg3A6nfo,1387
|
|
10
|
-
struct_frame/boilerplate/c/struct_frame_gen.h,sha256=rsuYGesEv1rWzSU1z6ybG-1e95RuVR7_IiR1mGLhYpQ,14
|
|
11
|
-
struct_frame/boilerplate/c/struct_frame_parser.h,sha256=5WP-0fH8BbqTeRUdzAye0Qh6gPBNHwVUocB3-gn5MOE,3005
|
|
12
|
-
struct_frame/boilerplate/c/struct_frame_types.h,sha256=5aJUQ_cbVPM9drdRfo1gmN46-PiAtICAZYrpVjmHaJA,1684
|
|
13
|
-
struct_frame/boilerplate/py/struct_frame_parser.py,sha256=txqaYNs5KFgnOsxRIbF3FGMwwtx0-6ynEDjOTy8LcU0,3607
|
|
14
|
-
struct_frame/boilerplate/ts/struct_frame.ts,sha256=botKdIKVP7Bi6BJdXfIZaGAmoATnuj54LxZxc4DAWqM,2252
|
|
15
|
-
struct_frame/boilerplate/ts/struct_frame_gen.ts,sha256=KAZitCUBeE8k0LSYLfOvR1GfG9JWDJUEDtmAOvOUAX0,168
|
|
16
|
-
struct_frame/boilerplate/ts/struct_frame_parser.ts,sha256=6eTbafomqTsX3Fvfn82rxNQMxu4PwTaPug38xw4wrhE,3523
|
|
17
|
-
struct_frame/boilerplate/ts/struct_frame_types.ts,sha256=aBtxVI2lUJKGPTtJAOpbStpS2sXSKvd4XWCIsOnaMk8,2130
|
|
18
|
-
struct_frame-0.0.24.dist-info/METADATA,sha256=IfG-TS9rPWYr5ovqto2FXPP1VYo5u_j-OLahTg7M5rU,745
|
|
19
|
-
struct_frame-0.0.24.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
20
|
-
struct_frame-0.0.24.dist-info/licenses/LICENSE,sha256=UjbLtGfcHCIqJg9UzEVGoNW8fyX4Ah9ZbsuAmJ_vhmk,1094
|
|
21
|
-
struct_frame-0.0.24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|