cannect 1.0.0__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.
- cannect/__init__.py +30 -0
- cannect/api/__init__.py +0 -0
- cannect/config.py +114 -0
- cannect/core/__init__.py +0 -0
- cannect/core/ascet/__init__.py +3 -0
- cannect/core/ascet/amd.py +698 -0
- cannect/core/ascet/formula.py +33 -0
- cannect/core/ascet/oid.py +29 -0
- cannect/core/ascet/ws.py +154 -0
- cannect/core/can/__init__.py +2 -0
- cannect/core/can/ascet/__init__.py +3 -0
- cannect/core/can/ascet/_db2code.py +344 -0
- cannect/core/can/ascet/_db2elem.py +399 -0
- cannect/core/can/ascet/comdef.py +256 -0
- cannect/core/can/ascet/comrx.py +139 -0
- cannect/core/can/ascet/diag.py +691 -0
- cannect/core/can/db/__init__.py +4 -0
- cannect/core/can/db/reader.py +148 -0
- cannect/core/can/db/schema.py +269 -0
- cannect/core/can/db/specification/__init__.py +0 -0
- cannect/core/can/db/specification/message.py +230 -0
- cannect/core/can/db/specification/styles.py +81 -0
- cannect/core/can/db/specification/wrapper.py +161 -0
- cannect/core/can/db/vcs.py +104 -0
- cannect/core/can/rule.py +229 -0
- cannect/core/can/testcase/__init__.py +0 -0
- cannect/core/can/testcase/unitcase/__init__.py +0 -0
- cannect/core/can/testcase/unitcase/asw2can.py +48 -0
- cannect/core/can/testcase/unitcase/decode.py +63 -0
- cannect/core/can/testcase/unitcase/diagnosis.py +479 -0
- cannect/core/can/testcase/unitcase/encode.py +60 -0
- cannect/core/ir/__init__.py +2 -0
- cannect/core/ir/changehistory.py +310 -0
- cannect/core/ir/delivereables.py +71 -0
- cannect/core/ir/diff.py +97 -0
- cannect/core/ir/ir.py +581 -0
- cannect/core/ir/sdd.py +148 -0
- cannect/core/mdf.py +66 -0
- cannect/core/subversion.py +136 -0
- cannect/core/testcase/__init__.py +3 -0
- cannect/core/testcase/plotter.py +181 -0
- cannect/core/testcase/style.py +981 -0
- cannect/core/testcase/testcase.py +160 -0
- cannect/core/testcase/unitcase.py +227 -0
- cannect/errors.py +20 -0
- cannect/schema/__init__.py +5 -0
- cannect/schema/candb.py +226 -0
- cannect/schema/datadictionary.py +60 -0
- cannect/utils/__init__.py +3 -0
- cannect/utils/excel.py +29 -0
- cannect/utils/logger.py +81 -0
- cannect/utils/ppt.py +236 -0
- cannect/utils/tools.py +207 -0
- cannect-1.0.0.dist-info/METADATA +214 -0
- cannect-1.0.0.dist-info/RECORD +58 -0
- cannect-1.0.0.dist-info/WHEEL +5 -0
- cannect-1.0.0.dist-info/licenses/LICENSE +21 -0
- cannect-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from cannect.schema.datadictionary import DataDictionary
|
|
2
|
+
from xml.etree.ElementTree import ElementTree
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def formula_dictionary(filepath:str) -> DataDictionary:
|
|
6
|
+
tree = ElementTree(file=filepath)
|
|
7
|
+
data = DataDictionary()
|
|
8
|
+
for tag in tree.iter('Formula'):
|
|
9
|
+
if tag.get('type') != '5 Parameters':
|
|
10
|
+
continue
|
|
11
|
+
obj = DataDictionary()
|
|
12
|
+
obj.unit = tag.get('unit')
|
|
13
|
+
for n, param in enumerate(tag.iter('Parameter'), start=1):
|
|
14
|
+
obj[f'p{n}'] = param.get('value')
|
|
15
|
+
|
|
16
|
+
p1, p2, p3, p4, p5 = float(obj.p1), float(obj.p2), float(obj.p3), float(obj.p4), float(obj.p5)
|
|
17
|
+
if p3 != 0:
|
|
18
|
+
obj.quantization = p2 / p3
|
|
19
|
+
obj.offset = -p4 / p3
|
|
20
|
+
elif p1 != 0:
|
|
21
|
+
obj.quantization = abs(p4 / p1)
|
|
22
|
+
obj.offset = (-p4 * p5 - p2) / p1
|
|
23
|
+
else:
|
|
24
|
+
KeyError(f'Unknown Case For {tag.get("name")}')
|
|
25
|
+
data[tag.get('name')] = obj
|
|
26
|
+
return data
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
file = r"D:\ETASData\ASCET6.1\Export\_Formula\HNB_I4GDI_EU7.xml"
|
|
31
|
+
formula = formula_dictionary(file)
|
|
32
|
+
print(formula)
|
|
33
|
+
print(formula.k_q0p000244)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from random import choice, choices, shuffle
|
|
2
|
+
from time import time
|
|
3
|
+
from typing import List, Union
|
|
4
|
+
import string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def generateOID(count:int=1) -> Union[str, List[str]]:
|
|
8
|
+
syntax1 = [
|
|
9
|
+
'1ngg01pp', '1ngg00p9', '03000000', '1ngg01a0', '1ngg0140',
|
|
10
|
+
'000g00p9', '04136psg', '00000300', '038g01ah', '000g0136',
|
|
11
|
+
'1ngg013h', '1ngg019n', '1ngg01ah', '000g019n'
|
|
12
|
+
]
|
|
13
|
+
syntax2 = ['1og7', '1mo7', '1o07', '1ng7', '1o87', '1no7', '1n87', '1n07', '1mg7']
|
|
14
|
+
|
|
15
|
+
oids = []
|
|
16
|
+
for n in range(count):
|
|
17
|
+
charset = string.ascii_lowercase + string.digits # 'abcdefghijklmnopqrstuvwxyz0123456789'
|
|
18
|
+
timestamp = str(int(time() * 1000000))
|
|
19
|
+
randomkey = list(timestamp[-8:]) + choices(charset, k=5)
|
|
20
|
+
shuffle(randomkey)
|
|
21
|
+
oids.append(f'_040g{choice(syntax1)}{choice(syntax2)}{"".join(randomkey)}')
|
|
22
|
+
if len(oids) == 1:
|
|
23
|
+
return oids[0]
|
|
24
|
+
return oids
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
for oid in generateOID(100):
|
|
29
|
+
print(oid)
|
cannect/core/ascet/ws.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from cannect.core.ascet import AmdIO, AmdSC
|
|
2
|
+
from cannect.core.subversion import Subversion
|
|
3
|
+
from cannect.config import env
|
|
4
|
+
from cannect.errors import AscetWorspaceFormatError, AmdDuplicationError, AmdNotFoundError
|
|
5
|
+
from pandas import DataFrame, concat
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Union
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WorkspaceIO:
|
|
12
|
+
|
|
13
|
+
def __init__(self, path:str=""):
|
|
14
|
+
self.path = path = env.SVN_MODEL if not path else Path(path)
|
|
15
|
+
|
|
16
|
+
listdir = os.listdir(path)
|
|
17
|
+
if not "HNB_GASOLINE" in listdir:
|
|
18
|
+
raise AscetWorspaceFormatError('NO {HNB_GASOLINE} IN WORKSPACE DIRECTORY')
|
|
19
|
+
if not "HMC_ECU_Library" in listdir:
|
|
20
|
+
raise AscetWorspaceFormatError('NO {HMC_ECU_Library} IN WORKSPACE DIRECTORY')
|
|
21
|
+
|
|
22
|
+
fdb = ''
|
|
23
|
+
if '.svn' in listdir:
|
|
24
|
+
fdb = Path(path) / '.svn/wc.db'
|
|
25
|
+
for f in listdir:
|
|
26
|
+
if f.endswith('.aws'):
|
|
27
|
+
fdb = Path(path) / f
|
|
28
|
+
|
|
29
|
+
if not fdb:
|
|
30
|
+
raise AscetWorspaceFormatError('NO .aws OR wc.db IN WORKSPACE DIRECTORY')
|
|
31
|
+
|
|
32
|
+
if str(fdb).endswith('.db'):
|
|
33
|
+
db = Subversion.read_wcdb(fdb)
|
|
34
|
+
db = db[~db["local_relpath"].str.startswith("Personal")]
|
|
35
|
+
self.dbtype = 'wc'
|
|
36
|
+
else:
|
|
37
|
+
self.dbtype = 'ws'
|
|
38
|
+
# TODO
|
|
39
|
+
# .aws 파일 파싱
|
|
40
|
+
pass
|
|
41
|
+
self.db = db
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
def __getitem__(self, item):
|
|
45
|
+
return self.find(item)
|
|
46
|
+
|
|
47
|
+
def find(self, name:str) -> str:
|
|
48
|
+
# TODO
|
|
49
|
+
# .asw CASE 생성
|
|
50
|
+
if self.dbtype == 'ws':
|
|
51
|
+
pass
|
|
52
|
+
else:
|
|
53
|
+
if not name.endswith('.zip'):
|
|
54
|
+
name += '.zip'
|
|
55
|
+
query = self.db[self.db['kind'] == 'file'].copy()
|
|
56
|
+
query = query[query['local_relpath'].str.endswith(name)]
|
|
57
|
+
if query.empty:
|
|
58
|
+
raise AmdNotFoundError(f'MODULE {name} NOT FOUND')
|
|
59
|
+
if len(query) > 1:
|
|
60
|
+
raise AmdDuplicationError(rf'{query}\nMODULE {name} DUPLICATED: SPECIFY PARENT FOLDER')
|
|
61
|
+
return str(self.path / query.iloc[0]['local_relpath'])
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def HNB_GASOLINE(self) -> Path:
|
|
65
|
+
return self.path / 'HNB_GASOLINE'
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def HMC_ECU_Library(self) -> Path:
|
|
69
|
+
return self.path / 'HMC_ECU_Library'
|
|
70
|
+
|
|
71
|
+
def bcPath(self, n:Union[str, int]) -> str:
|
|
72
|
+
target = [path for path in os.listdir(self.HNB_GASOLINE) if str(n) in path]
|
|
73
|
+
if not target:
|
|
74
|
+
raise FileNotFoundError(f'#{n} BC Not Exist')
|
|
75
|
+
return str(self.HNB_GASOLINE / target[0])
|
|
76
|
+
|
|
77
|
+
def bcTree(self, n:Union[str, int]) -> DataFrame:
|
|
78
|
+
r"""
|
|
79
|
+
:param n:
|
|
80
|
+
:return:
|
|
81
|
+
|
|
82
|
+
출력 예시)
|
|
83
|
+
bc file layer1 layer2 layer3 path
|
|
84
|
+
0 _33_EnginePositionManagement CamPosA.zip CamPosition EdgeAdapt CamPosA D:\SVN\model\ascet\trunk\HNB_GASOLINE\_33_Engi...
|
|
85
|
+
1 _33_EnginePositionManagement CamOfsD.zip CamPosition OffsetDiagnosis CamOfsD D:\SVN\model\ascet\trunk\HNB_GASOLINE\_33_Engi...
|
|
86
|
+
2 _33_EnginePositionManagement CamSeg.zip CamPosition SegmentTime CamSeg D:\SVN\model\ascet\trunk\HNB_GASOLINE\_33_Engi...
|
|
87
|
+
... ... ... ... ...
|
|
88
|
+
29 _33_EnginePositionManagement EpmSv.zip ServiceLibrary EpmSvLib NaN D:\SVN\model\ascet\trunk\HNB_GASOLINE\_33_Engi...
|
|
89
|
+
30 _33_EnginePositionManagement CamSync.zip Syncronization CamPhaseSync CamSyn D:\SVN\model\ascet\trunk\HNB_GASOLINE\_33_Engi...
|
|
90
|
+
31 _33_EnginePositionManagement CrkSyn.zip Syncronization CrankPositionSync CrkSyn D:\SVN\model\ascet\trunk\HNB_GASOLINE\_33_Engi...
|
|
91
|
+
"""
|
|
92
|
+
path = self.bcPath(n)
|
|
93
|
+
data = []
|
|
94
|
+
for root, paths, files in os.walk(path):
|
|
95
|
+
for file in files:
|
|
96
|
+
data.append({
|
|
97
|
+
'bc': os.path.basename(path),
|
|
98
|
+
'file': file,
|
|
99
|
+
'path': os.path.join(root, file),
|
|
100
|
+
})
|
|
101
|
+
layers = [l for l in root.replace(path, "").split('/' if '/' in root else '\\') if l]
|
|
102
|
+
for n, layer in enumerate(layers):
|
|
103
|
+
data[-1].update({f'layer{n+1}': layer})
|
|
104
|
+
tree = DataFrame(data)
|
|
105
|
+
cols = [col for col in tree if not col == 'path'] + ['path']
|
|
106
|
+
return tree[cols]
|
|
107
|
+
|
|
108
|
+
def bcEL(self, n:Union[str, int]) -> DataFrame:
|
|
109
|
+
objs = []
|
|
110
|
+
tree = self.bcTree(n)
|
|
111
|
+
for i, row in tree.iterrows():
|
|
112
|
+
path = row['path']
|
|
113
|
+
amdsc = AmdSC(path)
|
|
114
|
+
amdio = AmdIO(amdsc.main)
|
|
115
|
+
frame = amdio.dataframe('Element')
|
|
116
|
+
# frame['bc'] = row['bc']
|
|
117
|
+
|
|
118
|
+
objs.append(frame)
|
|
119
|
+
data = concat(objs=objs, axis=0)
|
|
120
|
+
|
|
121
|
+
unique = data[data['scope'] == 'exported']
|
|
122
|
+
oids = dict(zip(unique['name'].values, unique['OID'].values))
|
|
123
|
+
def __eid(_row):
|
|
124
|
+
if _row.scope in ["exported"]:
|
|
125
|
+
return _row.OID
|
|
126
|
+
if _row["name"] in oids:
|
|
127
|
+
return oids[_row["name"]]
|
|
128
|
+
return None
|
|
129
|
+
data["UID"] = data.apply(__eid, axis=1)
|
|
130
|
+
return data
|
|
131
|
+
|
|
132
|
+
def bcIO(self, n:Union[str, int]) -> DataFrame:
|
|
133
|
+
el = self.bcEL(n).copy().set_index(keys='UID')
|
|
134
|
+
el = el[["model", "name", "unit", "modelType", "basicModelType", "kind", "scope"]]
|
|
135
|
+
im = el[el["scope"] == "imported"].copy()
|
|
136
|
+
ex = el[el["scope"] == "exported"].copy()
|
|
137
|
+
im["exportedBy"] = [ex.loc[i, "model"] if i in ex.index else "/* 외부 BC */" for i in im.index]
|
|
138
|
+
return concat([im, ex], axis=0)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if __name__ == "__main__":
|
|
143
|
+
from pandas import set_option
|
|
144
|
+
set_option('display.expand_frame_repr', False)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
io = WorkspaceIO()
|
|
148
|
+
print(io["CanHSFPCMD"])
|
|
149
|
+
# print(io.bcPath(33))
|
|
150
|
+
# print(io.bcTree(33))
|
|
151
|
+
# print(io.bcEL(33))
|
|
152
|
+
# print(io.bcIO(33))
|
|
153
|
+
|
|
154
|
+
# io.bcIO(33).to_clipboard()
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
from cannect.config import env
|
|
2
|
+
from cannect.core.can.rule import naming
|
|
3
|
+
from cannect.errors import CANDBError
|
|
4
|
+
from cannect.schema.candb import CanMessage, CanSignal
|
|
5
|
+
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from pandas import DataFrame, Series
|
|
8
|
+
from typing import Dict
|
|
9
|
+
import pandas as pd
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
INFO = lambda revision: f"""* COMPANY: {env['COMPANY']}
|
|
14
|
+
* DIVISION: {env['DIVISION']}
|
|
15
|
+
* AUTHOR: {env['USERNAME']}
|
|
16
|
+
* CREATED: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
17
|
+
* DB VERSION: {revision}
|
|
18
|
+
{env["COPYRIGHT"]}
|
|
19
|
+
|
|
20
|
+
THIS MODEL IS AUTO-GENERATED.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
INLINE = f"""
|
|
24
|
+
/* ----------------------------------------------------------------------------------------------------
|
|
25
|
+
Inline Function : Memory Copy
|
|
26
|
+
---------------------------------------------------------------------------------------------------- */
|
|
27
|
+
inline void __memcpy(void *dst, const void *src, size_t len) {{
|
|
28
|
+
size_t i;
|
|
29
|
+
char *d = dst;
|
|
30
|
+
const char *s = src;
|
|
31
|
+
for (i = 0; i < len; i++)
|
|
32
|
+
d[i] = s[i];
|
|
33
|
+
}}
|
|
34
|
+
|
|
35
|
+
/* ----------------------------------------------------------------------------------------------------
|
|
36
|
+
Inline Function : Message Counter Check
|
|
37
|
+
---------------------------------------------------------------------------------------------------- */
|
|
38
|
+
inline void cntvld(uint8 *vld, uint8 *timer, uint8 recv, uint8 calc, uint8 thres) {{
|
|
39
|
+
if ( recv == calc ) {{
|
|
40
|
+
*timer += 1;
|
|
41
|
+
if ( *timer >= thres ) {{
|
|
42
|
+
*timer = thres;
|
|
43
|
+
*vld = 0;
|
|
44
|
+
}}
|
|
45
|
+
}}
|
|
46
|
+
else {{
|
|
47
|
+
*timer = 0;
|
|
48
|
+
*vld = 1;
|
|
49
|
+
}}
|
|
50
|
+
}}
|
|
51
|
+
|
|
52
|
+
/* ----------------------------------------------------------------------------------------------------
|
|
53
|
+
Inline Function : CRC Check
|
|
54
|
+
---------------------------------------------------------------------------------------------------- */
|
|
55
|
+
inline void crcvld(uint8 *vld, uint8 *timer, uint8 recv, uint8 calc, uint8 thres) {{
|
|
56
|
+
if ( recv == calc ) {{
|
|
57
|
+
*timer = 0;
|
|
58
|
+
*vld = 1;
|
|
59
|
+
}}
|
|
60
|
+
else {{
|
|
61
|
+
*timer += 1;
|
|
62
|
+
if ( *timer >= thres ) {{
|
|
63
|
+
*timer = thres;
|
|
64
|
+
*vld = 0;
|
|
65
|
+
}}
|
|
66
|
+
}}
|
|
67
|
+
}}
|
|
68
|
+
|
|
69
|
+
/* ----------------------------------------------------------------------------------------------------
|
|
70
|
+
Inline Function : Alive Counter Check
|
|
71
|
+
---------------------------------------------------------------------------------------------------- */
|
|
72
|
+
inline void alvvld(uint8 *vld, uint8 *timer, uint8 recv, uint8 calc, uint8 thres) {{
|
|
73
|
+
if ( ( recv == calc ) || ( (recv - calc) > 10 ) ) {{
|
|
74
|
+
*timer += 1;
|
|
75
|
+
if ( *timer >= thres ) {{
|
|
76
|
+
*timer = thres;
|
|
77
|
+
*vld = 0;
|
|
78
|
+
}}
|
|
79
|
+
}}
|
|
80
|
+
else {{
|
|
81
|
+
*timer = 0;
|
|
82
|
+
*vld = 1;
|
|
83
|
+
}}
|
|
84
|
+
}}
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def SignalDecode(signal:CanSignal, rule:naming=None) -> str:
|
|
89
|
+
if signal.empty:
|
|
90
|
+
return ""
|
|
91
|
+
if not rule:
|
|
92
|
+
rule = naming(signal.Message)
|
|
93
|
+
name = signal.SignalRenamed if signal.SignalRenamed else signal.name
|
|
94
|
+
size = 8 if signal.Length <= 8 else 16 if signal.Length <= 16 else 32
|
|
95
|
+
buff = f'{rule.tag}.B.{name}'
|
|
96
|
+
elem = f'{name}_Can'
|
|
97
|
+
if signal.Message == "L_BMS_22_100ms" and signal.Length == 32:
|
|
98
|
+
return f"""{elem} = (uint32)({buff}_1
|
|
99
|
+
+ ({buff}_2 << 8)
|
|
100
|
+
+ ({buff}_3 << 16)
|
|
101
|
+
+ ({buff}_4 << 24));"""
|
|
102
|
+
|
|
103
|
+
if signal["Value Type"].lower() == "unsigned":
|
|
104
|
+
return f"{elem} = (uint{size}){buff};"
|
|
105
|
+
|
|
106
|
+
if signal.SignedProcessing.lower() == "complement":
|
|
107
|
+
if signal.Length in [8, 16, 32]:
|
|
108
|
+
return f"{elem} = (sint{size}){buff};"
|
|
109
|
+
else:
|
|
110
|
+
msb = f"( {buff} >> {signal.Length - 1} ) && 1"
|
|
111
|
+
neg = f"(sint{size})({buff} | {hex(2 ** size - 2 ** signal.Length).upper().replace('X', 'x')})"
|
|
112
|
+
pos = f"(sint{size}){buff}"
|
|
113
|
+
return f"{elem} = {msb} ? {neg} : {pos};"
|
|
114
|
+
elif signal.SignedProcessing.lower() == "absolute":
|
|
115
|
+
msb = f"( {buff} >> {signal.Length - 1} ) && 1"
|
|
116
|
+
neg = f"(sint{size})( (~{buff} + 1) | {hex(2 ** size - 2 ** (signal.Length - 1)).upper().replace('X', 'x')} )"
|
|
117
|
+
pos = f"(sint{size}){buff}"
|
|
118
|
+
|
|
119
|
+
syn = f"{elem} = {msb} ? {neg} : {pos};"
|
|
120
|
+
rtz = f"if ( {buff} == {hex(2 ** (signal.Length - 1)).upper().replace('X', 'x')} ) {{ {elem} = 0x0; }}"
|
|
121
|
+
|
|
122
|
+
if str(signal.name) in ["TCU_TqRdctnVal", "TCU_EngTqLimVal", "L_TCU_TqRdctnVal", "L_TCU_EngTqLimVal"]:
|
|
123
|
+
syn += f'\n{rtz}'
|
|
124
|
+
return syn
|
|
125
|
+
else:
|
|
126
|
+
raise CANDBError("Signed Signal must be specified the processing method.")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class MessageValidator:
|
|
130
|
+
def __init__(self, alv_or_crc:CanSignal, rule:naming=None):
|
|
131
|
+
var = f'{alv_or_crc.name}_Can'
|
|
132
|
+
calc =f'{alv_or_crc.name}Calc'
|
|
133
|
+
self.decode = SignalDecode(alv_or_crc, rule)
|
|
134
|
+
self.encode = ''
|
|
135
|
+
if alv_or_crc.empty:
|
|
136
|
+
self.calcCode = ''
|
|
137
|
+
self.validate = ''
|
|
138
|
+
return
|
|
139
|
+
elif alv_or_crc.isCrc():
|
|
140
|
+
self.calcCode = f'{calc} = CRC{alv_or_crc.Length}bit_Calculator.calc( {alv_or_crc.ID}, {rule.tag}.Data, {rule.dlc} );'
|
|
141
|
+
self.validate = f'crcvld( &{rule.crcValid}, &{rule.crcTimer}, {var}, {calc}, {rule.thresholdTime} );'
|
|
142
|
+
elif alv_or_crc.isAliveCounter():
|
|
143
|
+
self.calcCode = f'{calc} = {var};'
|
|
144
|
+
self.validate = f'alvvld( &{rule.aliveCountValid}, &{rule.aliveCountTimer}, {var}, {calc}, {rule.thresholdTime} );'
|
|
145
|
+
else:
|
|
146
|
+
pass
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class MessageCode:
|
|
151
|
+
SEND_TYPE = {
|
|
152
|
+
"P": "Periodic",
|
|
153
|
+
"PE": "Periodic On Event",
|
|
154
|
+
"EC": "Event On Change",
|
|
155
|
+
"EW": "Event On Write",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
def __init__(self, message:CanMessage, exclude_tsw:bool=True):
|
|
159
|
+
self.message = message
|
|
160
|
+
self.name = name = str(message.name)
|
|
161
|
+
self.names = naming(self.name)
|
|
162
|
+
self.exclude_tsw = exclude_tsw
|
|
163
|
+
|
|
164
|
+
self.srv_name = lambda md: f"#define COMPILE_UNUSED__{md.upper()}_IMPL__{name}"
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
def __getitem__(self, item):
|
|
168
|
+
return self.message[item]
|
|
169
|
+
|
|
170
|
+
def messageAlign(self) -> list:
|
|
171
|
+
buffer = [f"Reserved_{n // 8}" for n in range(8 * self["DLC"])]
|
|
172
|
+
self.message.ITERATION_INCLUDES_CRC = self.message.ITERATION_INCLUDES_ALIVECOUNTER = True
|
|
173
|
+
for sig in self.message:
|
|
174
|
+
index = sig.StartBit
|
|
175
|
+
while index < (sig.StartBit + sig.Length):
|
|
176
|
+
buffer[index] = sig.SignalRenamed if sig.SignalRenamed else sig.Signal
|
|
177
|
+
index += 1
|
|
178
|
+
|
|
179
|
+
# Exception
|
|
180
|
+
cnt = {}
|
|
181
|
+
for n, sig in enumerate(buffer.copy()):
|
|
182
|
+
if sig.startswith('xEV_Tot'):
|
|
183
|
+
if not sig in cnt:
|
|
184
|
+
cnt[sig] = 0
|
|
185
|
+
buffer[n] = f'{buffer[n]}_{(cnt[sig] // 8) + 1}'
|
|
186
|
+
cnt[sig] += 1
|
|
187
|
+
|
|
188
|
+
aligned = []
|
|
189
|
+
count, name = 0, buffer[0]
|
|
190
|
+
for n, sig in enumerate(buffer):
|
|
191
|
+
if sig == name:
|
|
192
|
+
count += 1
|
|
193
|
+
if n == 8 * self["DLC"] - 1:
|
|
194
|
+
aligned.append(f"uint32 {name} : {count};")
|
|
195
|
+
else:
|
|
196
|
+
aligned.append(f"uint32 {name} : {count};")
|
|
197
|
+
count, name = 1, sig
|
|
198
|
+
|
|
199
|
+
eigen = []
|
|
200
|
+
aligned_copy = aligned.copy()
|
|
201
|
+
for n, struct in enumerate(aligned):
|
|
202
|
+
label = struct.split(" : ")[0].replace("uint32 ", "")
|
|
203
|
+
if label in eigen:
|
|
204
|
+
aligned_copy[n] = aligned_copy[n].replace(label, f'{label}_{eigen.count(label)}')
|
|
205
|
+
eigen.append(label)
|
|
206
|
+
|
|
207
|
+
return aligned_copy
|
|
208
|
+
|
|
209
|
+
def signalDecode(self, spliter:str="\n\t") -> str:
|
|
210
|
+
code = []
|
|
211
|
+
for sig in self.message:
|
|
212
|
+
if sig.isAliveCounter() or sig.isCrc():
|
|
213
|
+
continue
|
|
214
|
+
code.append(SignalDecode(sig, self.names))
|
|
215
|
+
return spliter.join(code)
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def def_name(self) -> str:
|
|
219
|
+
chn = "PL2" if self["Channel"] == "H" else "PL1" if self["Channel"] == "L" else "P"
|
|
220
|
+
bsw = f"CAN_MSGNAME_{self['Message']}_{chn}"
|
|
221
|
+
if self["Message"] == "EGSNXUpStream_Data":
|
|
222
|
+
bsw = "CAN_MSGNAME_EGSNXUpStream_B1_data_1"
|
|
223
|
+
if self["Message"] == "EGSNXUpStream_Req":
|
|
224
|
+
bsw = "CAN_MSGNAME_EGSNXUpStream_B1_Rqst"
|
|
225
|
+
if self["Message"] == "HCU_11_P_00ms":
|
|
226
|
+
bsw = "CAN_MSGNAME_HCU_11_00ms_P"
|
|
227
|
+
if self["Message"] == "HCU_11_H_00ms":
|
|
228
|
+
bsw = "CAN_MSGNAME_HCU_11_00ms_PL2"
|
|
229
|
+
if self["Message"] == "IMU_01_10ms":
|
|
230
|
+
bsw = "CAN_MSGNAME_YRS_01_10ms_P"
|
|
231
|
+
if self.message.isTsw() and self.exclude_tsw:
|
|
232
|
+
bsw = 255
|
|
233
|
+
asw = f'MSGNAME_{naming(self["Message"]).tag}'
|
|
234
|
+
return f"#define {asw}\t{bsw}"
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def struct(self) -> str:
|
|
238
|
+
aligned = '\n\t\t'.join(self.messageAlign())
|
|
239
|
+
return f"""
|
|
240
|
+
/* ------------------------------------------------------------------------------
|
|
241
|
+
MESSAGE\t\t\t: {self["Message"]}
|
|
242
|
+
MESSAGE ID\t\t: {self["ID"]}
|
|
243
|
+
MESSAGE DLC\t: {self["DLC"]}
|
|
244
|
+
SEND TYPE\t\t: {self["Send Type"]}
|
|
245
|
+
-------------------------------------------------------------------------------- */
|
|
246
|
+
typedef union {{
|
|
247
|
+
uint8 Data[{self["DLC"]}];
|
|
248
|
+
struct {{
|
|
249
|
+
{aligned}
|
|
250
|
+
}} B;
|
|
251
|
+
}} CanFrm_{self.names.tag};"""
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
def method(self) -> str:
|
|
255
|
+
names = self.names
|
|
256
|
+
aliveCounter = MessageValidator(self.message.aliveCounter, names)
|
|
257
|
+
crc = MessageValidator(self.message.crc, names)
|
|
258
|
+
code = f"""
|
|
259
|
+
/* ------------------------------------------------------------------------------
|
|
260
|
+
MESSAGE\t\t\t: {self.name}
|
|
261
|
+
MESSAGE ID\t\t: {self["ID"]}
|
|
262
|
+
MESSAGE DLC\t: {self["DLC"]}
|
|
263
|
+
SEND TYPE\t\t: {self.SEND_TYPE[self["Send Type"]]}
|
|
264
|
+
VERSION\t\t\t: {self["Version"]}
|
|
265
|
+
-------------------------------------------------------------------------------- */
|
|
266
|
+
if ( CanFrm_Recv( MSGNAME_{names.tag}, {names.buffer}, &{names.dlc} ) == CAN_RX_UPDATED ) {{
|
|
267
|
+
|
|
268
|
+
CanFrm_{names.tag} {names.tag} = {{0, }};
|
|
269
|
+
__memcpy( {names.tag}.Data, {names.buffer}, {names.dlc} );
|
|
270
|
+
|
|
271
|
+
{ crc.decode }
|
|
272
|
+
{ crc.calcCode }
|
|
273
|
+
{ aliveCounter.decode }
|
|
274
|
+
|
|
275
|
+
{ self.signalDecode() }
|
|
276
|
+
|
|
277
|
+
{ names.counter }++;
|
|
278
|
+
}}
|
|
279
|
+
|
|
280
|
+
cntvld( &{names.messageCountValid}, &{names.messageCountTimer}, {names.counter}, {names.counterCalc}, {names.thresholdTime} );
|
|
281
|
+
{ crc.validate }
|
|
282
|
+
{ aliveCounter.validate }
|
|
283
|
+
|
|
284
|
+
{ names.counterCalc } = { names.counter };
|
|
285
|
+
{ aliveCounter.calcCode }
|
|
286
|
+
"""
|
|
287
|
+
pcode = code[1:].splitlines()
|
|
288
|
+
ccode = []
|
|
289
|
+
for n, line in enumerate(pcode):
|
|
290
|
+
if n:
|
|
291
|
+
prev_line = pcode[n-1].replace("\t", "").replace(" ", "")
|
|
292
|
+
curr_line = line.replace("\t", "").replace(" ", "")
|
|
293
|
+
if prev_line == curr_line == "":
|
|
294
|
+
continue
|
|
295
|
+
ccode.append(line)
|
|
296
|
+
return "\n".join(ccode)
|
|
297
|
+
|
|
298
|
+
def to_rx(self, model: str) -> str:
|
|
299
|
+
tab, i = '\t', 0
|
|
300
|
+
send_type = {
|
|
301
|
+
"P": "Periodic",
|
|
302
|
+
"PE": "Periodic On Event",
|
|
303
|
+
"EC": "Event On Change",
|
|
304
|
+
"EW": "Event On Write",
|
|
305
|
+
}
|
|
306
|
+
syntax = f"""
|
|
307
|
+
/* ------------------------------------------------
|
|
308
|
+
MESSAGE\t\t\t: {self["Message"]}
|
|
309
|
+
MESSAGE ID\t\t: {self["ID"]}
|
|
310
|
+
MESSAGE DLC\t: {self["DLC"]}
|
|
311
|
+
SEND TYPE\t\t: {send_type[self["Send Type"]]}
|
|
312
|
+
CHANNEL\t\t\t: {self["Channel"]}-CAN
|
|
313
|
+
-------------------------------------------------- */"""
|
|
314
|
+
if self["SystemConstant"]:
|
|
315
|
+
syntax += f"\n#if ( {self['SystemConstant']} )"
|
|
316
|
+
if self["Codeword"]:
|
|
317
|
+
syntax += f"\nif ( {self['Codeword']} ) {{"
|
|
318
|
+
i += 1
|
|
319
|
+
syntax += f"\n{tab * i}{model.upper()}_IMPL__{self['Message']}();\n"
|
|
320
|
+
if self["Codeword"]:
|
|
321
|
+
syntax += f"}}\n"
|
|
322
|
+
if self["SystemConstant"]:
|
|
323
|
+
syntax += f"#endif\n"
|
|
324
|
+
return syntax
|
|
325
|
+
|
|
326
|
+
@classmethod
|
|
327
|
+
def method_contains_message(cls, context: Dict[str, str]) -> DataFrame:
|
|
328
|
+
status = {}
|
|
329
|
+
for method, code in context.items():
|
|
330
|
+
if code is None:
|
|
331
|
+
status[method] = None
|
|
332
|
+
else:
|
|
333
|
+
fs = [f.split("__")[-1] for f in re.findall(r'\bCOMDEF_\w*', code)]
|
|
334
|
+
status[method] = Series(index=fs, data=fs)
|
|
335
|
+
return pd.concat(status, axis=1)
|
|
336
|
+
|
|
337
|
+
if __name__ == "__main__":
|
|
338
|
+
from pyems.candb import CAN_DB
|
|
339
|
+
|
|
340
|
+
testDB = CAN_DB.to_developer_mode("HEV")
|
|
341
|
+
|
|
342
|
+
code = MessageCode(testDB.messages["L_BMS_22_100ms"])
|
|
343
|
+
print(code.def_name)
|
|
344
|
+
print(code.method)
|