forked from OpenCyphal/public_regulated_data_types
-
Notifications
You must be signed in to change notification settings - Fork 1
/
test.py
executable file
·115 lines (88 loc) · 3.93 KB
/
test.py
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
#!/usr/bin/env python3
import sys
import time
import string
import pydsdl
from functools import partial
MAX_SERIALIZED_BIT_LENGTH = 313 * 8 # See README
MAX_LINE_LENGTH = 120
HEADER_COMMENT_NOT_REQUIRED_IF_SMALLER_THAN = 100
ALLOWED_CHARACTERS = set(string.digits + string.ascii_letters + string.punctuation + ' ')
def die_at(ty, line_index, *text):
prefix = '%s:%d:' % (ty.source_file_path, line_index + 1)
print(prefix, *text, file=sys.stderr)
sys.exit(1)
def on_print(file_path, line, value):
print('%s:%d: %s' % (file_path, line, value), file=sys.stderr)
def compute_max_num_frames_canfd(bit_length):
b = (bit_length + 7) // 8
if b <= 63:
return 1
else:
return (b + 2 + 62) // 63
started_at = time.monotonic()
ns_list = [
'uavcan',
'reg',
]
output = []
for ns in ns_list:
output += pydsdl.read_namespace(ns, ns_list, print_output_handler=on_print)
elapsed_time = time.monotonic() - started_at
print('Full data type name'.center(58),
'FSID'.center(5),
'CAN FD fr'.center(9))
for t in output:
num_frames_to_str = lambda x: str(x) if x > 1 else ' ' # Return empty for single-frame transfers
if isinstance(t, pydsdl.ServiceType):
max_canfd_frames = ' '.join([
num_frames_to_str(compute_max_num_frames_canfd(max(x.bit_length_set)))
for x in (t.request_type, t.response_type)
])
else:
max_canfd_frames = num_frames_to_str(compute_max_num_frames_canfd(max(t.bit_length_set)))
print(str(t).ljust(58),
str(t.fixed_port_id if t.has_fixed_port_id else '').rjust(5),
max_canfd_frames.rjust(7) + ' ')
print('%d data types in %.1f seconds' % (len(output), elapsed_time),
file=sys.stderr)
for t in output:
text = open(t.source_file_path).read()
for index, line in enumerate(text.split('\n')):
line = line.strip('\r\n')
abort = partial(die_at, t, index)
# Check header comment.
if index == 0 and not line.startswith('# '):
if len(t.attributes) > 2 or len(text) >= HEADER_COMMENT_NOT_REQUIRED_IF_SMALLER_THAN:
abort('This definition is not exempted from the header comment requirement')
# Check trailing comment placement.
# TODO: this test breaks on string literals containing "#".
if not line.startswith('#') and '#' in line and ' #' not in line:
abort('Trailing line comments shall be separated from the preceding text with at least two spaces')
if line != '#' and '#' in line and '# ' not in line:
abort('The text of a comment shall be separated from the comment character with a single space')
if line.endswith(' '):
abort('Trailing spaces are not permitted')
# Check line length limit
if len(line) > MAX_LINE_LENGTH:
abort('Line is too long:', len(line), '>', MAX_LINE_LENGTH, 'chars')
# Make sure we're not using any weird characters such as tabs or non-ASCII-printable
for char_index, char in enumerate(line):
if char not in ALLOWED_CHARACTERS:
abort('Disallowed character', repr(char), 'code', ord(char), 'at column', char_index + 1)
if not text.endswith('\n') or text.endswith('\n' * 2):
abort('A file shall contain exactly one blank line at the end')
def get_max_bit_length(ty) -> int:
if isinstance(ty, pydsdl.DelimitedType):
ty = ty.inner_type
if isinstance(ty, pydsdl.ServiceType):
return max(map(get_max_bit_length, [ty.request_type, ty.response_type]))
else:
return max(ty.bit_length_set)
for t in output:
max_bit_length = get_max_bit_length(t)
if max_bit_length > MAX_SERIALIZED_BIT_LENGTH:
text = open(t.source_file_path).read()
if '#pragma:no-bit-length-limit' not in text.replace(' ', ''):
print('The data type', t, 'exceeds the bit length limit of', MAX_SERIALIZED_BIT_LENGTH, file=sys.stderr)
sys.exit(1)