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.
Files changed (58) hide show
  1. cannect/__init__.py +30 -0
  2. cannect/api/__init__.py +0 -0
  3. cannect/config.py +114 -0
  4. cannect/core/__init__.py +0 -0
  5. cannect/core/ascet/__init__.py +3 -0
  6. cannect/core/ascet/amd.py +698 -0
  7. cannect/core/ascet/formula.py +33 -0
  8. cannect/core/ascet/oid.py +29 -0
  9. cannect/core/ascet/ws.py +154 -0
  10. cannect/core/can/__init__.py +2 -0
  11. cannect/core/can/ascet/__init__.py +3 -0
  12. cannect/core/can/ascet/_db2code.py +344 -0
  13. cannect/core/can/ascet/_db2elem.py +399 -0
  14. cannect/core/can/ascet/comdef.py +256 -0
  15. cannect/core/can/ascet/comrx.py +139 -0
  16. cannect/core/can/ascet/diag.py +691 -0
  17. cannect/core/can/db/__init__.py +4 -0
  18. cannect/core/can/db/reader.py +148 -0
  19. cannect/core/can/db/schema.py +269 -0
  20. cannect/core/can/db/specification/__init__.py +0 -0
  21. cannect/core/can/db/specification/message.py +230 -0
  22. cannect/core/can/db/specification/styles.py +81 -0
  23. cannect/core/can/db/specification/wrapper.py +161 -0
  24. cannect/core/can/db/vcs.py +104 -0
  25. cannect/core/can/rule.py +229 -0
  26. cannect/core/can/testcase/__init__.py +0 -0
  27. cannect/core/can/testcase/unitcase/__init__.py +0 -0
  28. cannect/core/can/testcase/unitcase/asw2can.py +48 -0
  29. cannect/core/can/testcase/unitcase/decode.py +63 -0
  30. cannect/core/can/testcase/unitcase/diagnosis.py +479 -0
  31. cannect/core/can/testcase/unitcase/encode.py +60 -0
  32. cannect/core/ir/__init__.py +2 -0
  33. cannect/core/ir/changehistory.py +310 -0
  34. cannect/core/ir/delivereables.py +71 -0
  35. cannect/core/ir/diff.py +97 -0
  36. cannect/core/ir/ir.py +581 -0
  37. cannect/core/ir/sdd.py +148 -0
  38. cannect/core/mdf.py +66 -0
  39. cannect/core/subversion.py +136 -0
  40. cannect/core/testcase/__init__.py +3 -0
  41. cannect/core/testcase/plotter.py +181 -0
  42. cannect/core/testcase/style.py +981 -0
  43. cannect/core/testcase/testcase.py +160 -0
  44. cannect/core/testcase/unitcase.py +227 -0
  45. cannect/errors.py +20 -0
  46. cannect/schema/__init__.py +5 -0
  47. cannect/schema/candb.py +226 -0
  48. cannect/schema/datadictionary.py +60 -0
  49. cannect/utils/__init__.py +3 -0
  50. cannect/utils/excel.py +29 -0
  51. cannect/utils/logger.py +81 -0
  52. cannect/utils/ppt.py +236 -0
  53. cannect/utils/tools.py +207 -0
  54. cannect-1.0.0.dist-info/METADATA +214 -0
  55. cannect-1.0.0.dist-info/RECORD +58 -0
  56. cannect-1.0.0.dist-info/WHEEL +5 -0
  57. cannect-1.0.0.dist-info/licenses/LICENSE +21 -0
  58. cannect-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,81 @@
1
+ from docx.document import Document
2
+ from docx.styles.styles import Styles
3
+ from docx.styles.style import ParagraphStyle
4
+ from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
5
+ from docx.enum.style import WD_STYLE_TYPE
6
+ from docx.shared import RGBColor, Pt, Inches
7
+
8
+
9
+
10
+
11
+ class CustomStyle:
12
+
13
+ def __init__(self, doc:Document):
14
+ self.doc = doc
15
+ return
16
+
17
+ @property
18
+ def title(self) -> ParagraphStyle:
19
+ if not "title" in self.doc.styles:
20
+ style = self.doc.styles.add_style("title", WD_PARAGRAPH_ALIGNMENT.CENTER)
21
+ style.font.name = "현대산스 Head"
22
+ style.font.size = Pt(28)
23
+ style.font.color.rgb = RGBColor(0, 0, 0)
24
+ style.font.bold = True
25
+ style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
26
+ return self.doc.styles['title']
27
+
28
+ @property
29
+ def overview_left(self) -> Styles:
30
+ if not "overview_left" in self.doc.styles:
31
+ style = self.doc.styles.add_style("overview_left", WD_PARAGRAPH_ALIGNMENT.CENTER)
32
+ style.font.name = "현대산스 Text"
33
+ style.font.size = Pt(11)
34
+ style.font.color.rgb = RGBColor(0, 0, 0)
35
+ style.font.bold = True
36
+ style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
37
+ return self.doc.styles['overview_left']
38
+
39
+ @property
40
+ def overview_right(self) -> Styles:
41
+ if not "overview_right" in self.doc.styles:
42
+ style = self.doc.styles.add_style("overview_right", WD_PARAGRAPH_ALIGNMENT.CENTER)
43
+ style.font.name = "현대산스 Text"
44
+ style.font.size = Pt(10)
45
+ style.font.color.rgb = RGBColor(0, 0, 0)
46
+ style.font.bold = False
47
+ style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
48
+ return self.doc.styles['overview_right']
49
+
50
+ @property
51
+ def footer(self) -> Styles:
52
+ if not "my_footer" in self.doc.styles:
53
+ style = self.doc.styles.add_style("my_footer", WD_STYLE_TYPE.PARAGRAPH)
54
+ style.font.name = "현대산스 Text"
55
+ style.font.size = Pt(10)
56
+ style.font.color.rgb = RGBColor(0, 0, 0)
57
+ style.font.bold = False
58
+ style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
59
+ return self.doc.styles['my_footer']
60
+
61
+ @property
62
+ def header_left(self) -> Styles:
63
+ if not "header_left" in self.doc.styles:
64
+ style = self.doc.styles.add_style("header_left", WD_PARAGRAPH_ALIGNMENT.CENTER)
65
+ style.font.name = "현대산스 Text"
66
+ style.font.size = Pt(8)
67
+ style.font.color.rgb = RGBColor(0, 0, 0)
68
+ style.font.bold = False
69
+ style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
70
+ return self.doc.styles['header_left']
71
+
72
+ @property
73
+ def header_right(self) -> Styles:
74
+ if not "header_right" in self.doc.styles:
75
+ style = self.doc.styles.add_style("header_right", WD_PARAGRAPH_ALIGNMENT.CENTER)
76
+ style.font.name = "현대산스 Text"
77
+ style.font.size = Pt(8)
78
+ style.font.color.rgb = RGBColor(0, 0, 0)
79
+ style.font.bold = False
80
+ style.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
81
+ return self.doc.styles['header_right']
@@ -0,0 +1,161 @@
1
+ from cannect.config import env
2
+ from cannect.core.can.db.reader import CANDBReader
3
+ from cannect.core.can.db.specification.styles import CustomStyle
4
+ from cannect.core.can.db.specification.message import Message
5
+ from cannect.core.subversion import Subversion
6
+ from cannect.utils import tools
7
+
8
+ from datetime import datetime
9
+ from docx import Document
10
+ from docx.parts.styles import Styles
11
+ from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
12
+ from docx.shared import RGBColor, Pt, Inches
13
+ from pandas import DataFrame
14
+ from pathlib import Path
15
+ from tqdm.auto import tqdm
16
+ from typing import Union
17
+ import os, time, site
18
+
19
+
20
+ class Specification:
21
+
22
+ def __init__(self, db:Union[CANDBReader, DataFrame]):
23
+ if isinstance(db, DataFrame):
24
+ db = CANDBReader(db)
25
+ self.db = db
26
+
27
+ if not (env.SVN_CANDB / r"사양서/resource").exists():
28
+ Subversion.update(env.SVN_CANDB / "사양서")
29
+
30
+ template = Path(site.getsitepackages()[1]) / 'docx/templates/default.docx'
31
+ if template.exists():
32
+ os.remove(template)
33
+ tools.copy_to(env.SVN_CANDB / r"사양서/resource/default", template.parent)
34
+ time.sleep(0.5)
35
+ os.rename(template.parent / 'default', template.parent / 'default.docx')
36
+ time.sleep(0.5)
37
+
38
+ self.doc = doc = Document()
39
+ self.styles = CustomStyle(doc)
40
+ return
41
+
42
+ def set_title(self):
43
+ self.doc.add_paragraph(
44
+ "\n자체제어기 EMS/ASW\n통신 사양서(CAN-FD)\n\n",
45
+ style=self.styles.title
46
+ )
47
+ return
48
+
49
+ def set_ci(self):
50
+ png = env.SVN_CANDB / r"사양서/resource/ci_cover.png"
51
+ paragraph = self.doc.add_paragraph()
52
+ runner = paragraph.add_run()
53
+ runner.add_picture(str(png), width=Inches(6))
54
+ paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
55
+ self.doc.add_paragraph("\n", style=self.styles.title)
56
+ return
57
+
58
+ def set_overview(self):
59
+ items = {
60
+ 'DATABASE': f"자체제어기/EMS CAN-FD {self.db.revision}",
61
+ 'COMPANY': env.COMPANY,
62
+ 'DIVISION': env.DIVISION,
63
+ 'RELEASE': datetime.now().strftime("%Y-%m-%d"),
64
+ }
65
+
66
+ table = self.doc.add_table(rows=len(items), cols=2)
67
+ table.style = 'Table Grid'
68
+ for n, (key, value) in enumerate(items.items()):
69
+ left = table.rows[n].cells[0]
70
+ left.width = Inches(1)
71
+ name = left.paragraphs[0]
72
+ name.style = self.styles.overview_left
73
+ name.text = key
74
+
75
+ right = table.rows[n].cells[1]
76
+ right.width = self.doc.sections[0].page_width
77
+ text = right.paragraphs[0]
78
+ text.style = self.styles.overview_right
79
+ text.text = value
80
+ return
81
+
82
+ def set_margin(self):
83
+ section = self.doc.sections[0]
84
+ section.left_margin = \
85
+ section.right_margin = Inches(0.5)
86
+ section.bottom_margin = \
87
+ section.top_margin = Inches(1)
88
+ return
89
+
90
+ def set_header(self, version:str):
91
+ header = self.doc.sections[0].header
92
+ for paragraph in header.paragraphs:
93
+ p = getattr(paragraph, "_element")
94
+ p.getparent().remove(p)
95
+
96
+ table = header.add_table(rows=1, cols=3, width=self.doc.sections[0].page_width)
97
+
98
+ left = table.rows[0].cells[0].paragraphs[0]
99
+ left.text = "자체제어기 EMS/ASW CAN-FD" + "\n" + f"DOC {version}"
100
+ left.style = self.styles.header_left
101
+
102
+ right = table.rows[0].cells[2].paragraphs[0]
103
+ right.text = env.DIVISION + "\n" + env.COMPANY
104
+ right.style = self.styles.header_right
105
+ return
106
+
107
+ def set_footer(self):
108
+ footer = self.doc.sections[0].footer
109
+ for paragraph in footer.paragraphs:
110
+ p = getattr(paragraph, "_element")
111
+ p.getparent().remove(p)
112
+ table = footer.add_table(rows=1, cols=1, width=self.doc.sections[0].page_width)
113
+ cell = table.rows[0].cells[0].paragraphs[0]
114
+ cell.text = env.COPYRIGHT
115
+ cell.style = self.styles.footer
116
+ return
117
+
118
+ def generate(self, filename:str):
119
+ if not filename.endswith('.docx'):
120
+ filename += '.docx'
121
+ objs = [(msg, obj) for msg, obj in self.db.messages.items()]
122
+ objs = sorted(objs, key=lambda x: x[0])
123
+
124
+ self.set_margin()
125
+ self.set_header(self.db.revision)
126
+ self.set_footer()
127
+ self.set_title()
128
+ self.set_ci()
129
+ self.set_overview()
130
+
131
+ self.doc.add_section()
132
+ message = Message(self.doc)
133
+ message.addHeading("EMS TRANSMIT")
134
+ transmit = tqdm([obj for _, obj in objs if obj["ECU"] == "EMS"])
135
+ for obj in transmit:
136
+ transmit.set_description(desc=f"{obj.name} 사양 생성")
137
+ message.addMessageHeading(obj)
138
+ message.addMessageSpec(obj)
139
+ message.addMessageLayout(obj)
140
+ message.addSignalList(obj)
141
+ message.addSignalProperty(obj)
142
+
143
+ message.addHeading("EMS RECEIVE")
144
+ receive = tqdm([obj for _, obj in objs if obj["ECU"] != "EMS"])
145
+ for obj in receive:
146
+ receive.set_description(desc=f"{obj.name} 사양 생성")
147
+ message.addMessageHeading(obj)
148
+ message.addMessageSpec(obj)
149
+ message.addMessageLayout(obj)
150
+ message.addSignalList(obj)
151
+ message.addSignalProperty(obj)
152
+
153
+ self.doc.save(env.DOWNLOADS / filename)
154
+ return
155
+
156
+
157
+ if __name__ == "__main__":
158
+ db = CANDBReader().mode('HEV')
159
+
160
+ spec = Specification(db)
161
+ spec.generate("TEST CAN SPEC")
@@ -0,0 +1,104 @@
1
+ from cannect.config import env
2
+ from cannect.core.can.db.schema import standardize
3
+ from cannect.core.subversion import Subversion
4
+ from cannect.errors import CANDBError
5
+ from cannect.utils.excel import ComExcel
6
+
7
+ from datetime import datetime
8
+ from pandas import DataFrame
9
+ from pathlib import Path
10
+ from pyperclip import paste
11
+ from typing import Callable
12
+ import os
13
+
14
+
15
+ class CANDBVcs:
16
+ """
17
+ CAN DB Version Control System
18
+ RPA를 위한 CAN DB 버전 시스템이다. json 포맷으로 구성된 데이터파일에 대한 버전이며
19
+ pandas DataFrame과 호환한다. 데이터파일의 집합은 외부로 공개되어서는 안 되며
20
+ 구동하는 호스트내 경로를 입력하여야 한다. 경로는 환경변수로 관리하거나 HMG 보안 처리된
21
+ 서버가 Check-Out된 경로를 사용한다.
22
+ """
23
+ silence :bool = False
24
+ logger :Callable = print
25
+
26
+ def __init__(self, filename:str=''):
27
+ if not filename:
28
+ filename = "자체제어기_KEFICO-EMS_CANFD.xlsx"
29
+ filepath = env.SVN_CANDB / filename
30
+ if not filepath.exists():
31
+ raise CANDBError(f'{filename} NOT EXISTS')
32
+
33
+ self.name = '.'.join(filename.split(".")[:-1])
34
+ self.filename = filename
35
+ self.filepath = filepath
36
+ self.history = history = Subversion.log(filepath)
37
+ self.revision = history.iloc[0, 0]
38
+ return
39
+
40
+ def _find_jsons(self) -> DataFrame:
41
+ data = []
42
+ for file in os.listdir((env.SVN_CANDB / "dev")):
43
+ if not file.endswith('.json'):
44
+ continue
45
+ if file.startswith(self.name) and file.endswith('.json'):
46
+ path = env.SVN_CANDB / f'dev/{file}'
47
+ data.append({
48
+ 'revision': file.split("_")[-1].replace(".json", ""),
49
+ 'datetime': datetime.fromtimestamp(os.path.getmtime(path)),
50
+ 'name': file,
51
+ 'path': path,
52
+ })
53
+ return DataFrame(data=data)
54
+
55
+ @property
56
+ def json(self) -> Path:
57
+ """
58
+ Excel CAN DB에 대한 최신 json 파일의 경로
59
+ :return:
60
+ """
61
+ jsons = self._find_jsons()
62
+ if jsons.empty:
63
+ raise CANDBError(f'NO MATCHED JSON DB FOR {{{self.filename}}} IN SVN')
64
+
65
+ jsons = jsons[jsons['name'].str.startswith(f'{self.name}_{self.revision}')] \
66
+ .sort_values(by='revision', ascending=False)
67
+ if jsons.empty:
68
+ raise CANDBError(f'NO MATCHED JSON DB FOR {{{self.filename}}} @{{{self.revision}}} IN SVN')
69
+ return Path(jsons.iloc[0]['path'])
70
+
71
+ def to_json(self, mode:str='auto'):
72
+ if mode == 'auto':
73
+ xl = ComExcel(self.filepath)
74
+ xl.ws.UsedRange.Copy()
75
+
76
+ try:
77
+ jsonpath = self.json
78
+ rev = str(int(jsonpath.name.split("@")[-1].split(".")[0]) + 1).zfill(2)
79
+ jsonpath = jsonpath.parent / f"{self.name}_{self.revision}@{rev}.json"
80
+ except CANDBError:
81
+ jsonpath = env.SVN_CANDB / f'dev/{self.name}_{self.revision}@01.json'
82
+
83
+ clipboard = [row.split("\t") for row in paste().split("\r\n")]
84
+ source = DataFrame(data=clipboard[1:], columns=standardize(clipboard[0]))
85
+ source = source[~source["ECU"].isna() & (source["ECU"] != "")]
86
+ source.to_json(jsonpath, orient='index')
87
+ if not self.silence:
88
+ self.logger("Manually Updated CAN DB from clipboard.")
89
+ self.logger(f"- Saved as : {jsonpath}")
90
+ return
91
+
92
+ # def commit_json(self):
93
+ # Subversion.commit(self.json, message="[CANNECT] AUTO-COMMIT CAN JSON DB")
94
+ # return
95
+
96
+ if __name__ == "__main__":
97
+ from pandas import set_option
98
+ set_option('display.expand_frame_repr', False)
99
+
100
+ cdb = CANDBVcs()
101
+ # cdb = CANDBVcs(r"G-PROJECT_KEFICO-EMS_CANFD.xlsx")
102
+ cdb.to_json()
103
+ print(cdb.json)
104
+ # cdb.commit_json()
@@ -0,0 +1,229 @@
1
+ from pandas import Series
2
+ from typing import Dict, Union, Hashable
3
+ import re
4
+
5
+
6
+ MESSAGE_RENAME = {
7
+ # NEW NAME: OLD NAME #
8
+ "SCU_DIAG": 'MHSG_STATE3',
9
+ "SCU_DIAG2": "MHSG_STATE4",
10
+ "SCU_FUNCTIONAL": "MHSG_STATE2",
11
+ "SCU_STATUS": "MHSG_STATE1",
12
+ "MASTER_CTRL_REQ": "EMS_MHSG1",
13
+ "MASTER_EXT_REQ": "EMS_MHSG2",
14
+ "MASTER_SPEED_REQ": "EMS_MHSG_SPEED",
15
+ "MASTER_STARTER_REQ": "EMS_MHSG_STARTER"
16
+ }
17
+ class naming(object):
18
+
19
+ def __init__(self, message: Union[str, Dict, Series, Hashable], hw:str='ICE'):
20
+
21
+ if isinstance(message, Series) or isinstance(message, Dict):
22
+ self.message = message["Message"]
23
+ elif isinstance(message, str):
24
+ self.message = message
25
+ elif isinstance(message, Hashable):
26
+ self.message = str(message)
27
+ else:
28
+ raise TypeError(f"Unknown type for message; {message}")
29
+ self.name = self.message
30
+
31
+ """
32
+ [예외 처리]
33
+ DB 상 이름이 매우 길거나 구 DB상 이름으로 개발되었으나 신 DB에서 이름이 바뀐 경우
34
+ """
35
+ if self.message.startswith("EGSNXUpStream"):
36
+ self.message = self.message.replace("UpStream", "")
37
+ if self.message == "Main_Status_Rear":
38
+ self.message = "NOx1Down"
39
+ if self.message == "O2_Rear":
40
+ self.message = "NOx1Ext"
41
+ if self.message.startswith("LEMS"):
42
+ self.message = f"L_{self.message[1:]}"
43
+ if self.message in MESSAGE_RENAME:
44
+ self.message = MESSAGE_RENAME[self.message]
45
+
46
+
47
+ """
48
+ [Message Name to Element Name : Base]
49
+ ASCET CAN 모델에 사용하는 Element Naming Rule 정의
50
+
51
+ 1. ASCET Element(Variable)에 사용하는 Message Name
52
+ Rule) split('_') --> capitalize() --> join()
53
+ * Under-Bar 없는 경우 capitalize()만 수행
54
+ * CAN-FD의 경우 메시지 주기 정보 제거
55
+ * Local CAN 식별자 L은 항상 대문자
56
+ * HEV 식별자 H는 항상 대문자
57
+ e.g.) Original Name | Rule Base Name
58
+ ----------------------------------------
59
+ ABS_ESC_01_10ms | AbsEsc01
60
+ HU_GW_PE_01 | HuGwPe01
61
+ FPCM11 | Fpcm11
62
+ EMS_14_200ms | Ems14
63
+ HTCU_04_10ms | HTcu04
64
+ L_HTCU_10_10ms | LHTcu10
65
+ """
66
+ splits = self.message.split('_')
67
+ splits = [split.lower().capitalize() for split in splits if not 'ms' in split]
68
+ self.base = base = ''.join(splits)
69
+ self.number = ''.join(re.findall(r'\d+', base))
70
+ if self.message.startswith("NOx"):
71
+ self.base = base = self.message
72
+ if "Htcu" in base:
73
+ self.base = base = base.replace("Htcu", "HTcu")
74
+ if self.message.startswith("L_EMS"):
75
+ self.base = base = f"L_EMS{splits[-1]}"
76
+ if self.message == "EMS_LDCBMS1":
77
+ self.base = base = "EmsLdcBms1"
78
+ if self.message.startswith("MHSG"):
79
+ self.base = base = f"StMhsg{splits[-1][-1]}"
80
+ self.pascal = base
81
+
82
+ self.root = root = ''.join([char for char in base if char.isalpha()])
83
+ if "Fd" in root:
84
+ self.root = root = root.replace("Fd", "")
85
+ if root == "BdcSmk":
86
+ self.root = root = "Bdc"
87
+ if self.message == "WHL_01_10ms":
88
+ self.root = root = "Abs"
89
+ for key in ["Bdc", "Hu", "Ilcu", "Pdc", "Sbcm", "Swrc"]:
90
+ if root.startswith(key):
91
+ self.root = root = key
92
+ break
93
+
94
+ """
95
+ 2. ASECT Hierarchy에 사용하는 Message Name
96
+ Rule) split('_') --> upper() --> join()
97
+ * Under-Bar 없는 경우 capitalize()만 수행
98
+ * CAN-FD의 경우 메시지 주기 정보 제거
99
+ e.g.) Original Name | Rule Base Name
100
+ ----------------------------------------
101
+ ABS_ESC_01_10ms | ABSESC01
102
+ HU_GW_PE_01 | HUGWPE01
103
+ FPCM11 | FPCM11
104
+ EMS_14_200ms | EMS14
105
+ HTCU_04_10ms | HTCU04
106
+ L_HTCU_10_10ms | LHTCU10
107
+ """
108
+ splits = [split.upper() for split in splits]
109
+ self.hierarchy = self.tag = self.upper = tag = ''.join(splits)
110
+ if self.message.startswith("MHSG"):
111
+ self.hierarchy = self.tag = self.upper = tag = f"MHSG{splits[-1][-1]}"
112
+
113
+ """
114
+ [Element Names]
115
+ 1. Buffer : Can_{base}Buf_A
116
+ 2. DLC : Can_{base}Size
117
+ 3. Counter : Can_ct{base}
118
+ 4. Counter Calc. : Can_ct{base}Calc
119
+ 4. Timeout : Can_tiFlt{base}_C
120
+ 5. Timer : Can_tiFlt{base}{Msg or Alv or Crc}
121
+ 6. Validity : FD_cVld{base}{Msg or Alv or Crc}
122
+ 7. Message Valid : FD_cVld{base}
123
+ 8. Status : Com_st{base}
124
+
125
+ """
126
+ self.method = f'_{self.message}'
127
+ self.buffer = f"Can_{base}Buf_A"
128
+ self.dlc = f"Can_{base}Size"
129
+ self.counter = f"Can_ct{base}"
130
+ self.counterCalc = f"Can_ct{base}Calc"
131
+ self.thresholdTime = f"Can_tiFlt{base}_C"
132
+
133
+ self.messageCountTimer = f"Can_tiFlt{base}Msg"
134
+ self.messageCountValid = f"FD_cVld{base}Msg"
135
+ self.aliveCountTimer = f"Can_tiFlt{base}Alv"
136
+ self.aliveCountValid = f"FD_cVld{base}Alv"
137
+ self.crcTimer = f"Can_tiFlt{base}Crc"
138
+ self.crcValid = f"FD_cVld{base}Crc"
139
+ self.messageValid = f"FD_cVld{base}"
140
+ self.status = f"Com_st{base}"
141
+
142
+ # 진단 모듈 사용 Naming
143
+ self.detectionThresholdTime = f"CanD_tiMonDet{root}_C"
144
+ self.detectionThreshold = f"CanD_ctDet{root}_C"
145
+ self.eepReset = f"CanD_RstEep{root}_C"
146
+
147
+ self.diagnosisChannel = f"CanD_cEnaDiagBus1"
148
+ self.detectionChannel = f"CanD_cEnaDetBus1{root}"
149
+ self.eepIndex = f"EEP_FD{tag}"
150
+ self.eep = f"EEP_stFD{tag}"
151
+ self.eepReader = f"CanD_stRdEep{base}"
152
+ self.fid = f"Fid_FD{tag}D"
153
+ self.debounceTime = f"CanD_tiFlt{base}_C"
154
+ self.debounceTimerMsg = f"CanD_tiFlt{base}Msg"
155
+ self.debounceTimerCrc = f"CanD_tiFlt{base}Crc"
156
+ self.debounceTimerAlv = f"CanD_tiFlt{base}Alv"
157
+ self.deveMsg = f"DEve_FD{base}Msg"
158
+ self.deveCrc = f"DEve_FD{base}Crc"
159
+ self.deveAlv = f"DEve_FD{base}Alv"
160
+ self.diagnosisMsg = f"CanD_cErr{base}Msg"
161
+ self.diagnosisCrc = f"CanD_cErr{base}Crc"
162
+ self.diagnosisAlv = f"CanD_cErr{base}Alv"
163
+ self.detectionCounter = f"CanD_ctDet{base}"
164
+ self.detectionEnable = f"CanD_cEnaDet{base}"
165
+ self.diagnosisEnable = f"CanD_cEnaDiag{base}"
166
+
167
+ """
168
+ 3. Exceptions
169
+ 1) DB 개정에 따라 메시지 이름이 변경되었으나 Binding 우려로 인해 기존 Naming을 유지해야 하는 경우
170
+ 2) 개발자 실수에 따라 양산 반영된 오기 Naming이 Binding 우려로 인해 기존 Naming을 유지해야 하는 경우
171
+ 3) DB 메시지 이름의 오타, 오탈 또는 길이 등의 사유로 인해 임의로 Naming을 변경한 경우
172
+ 4) 상기 사유 외 예외 처리가 인정되는 경우
173
+ """
174
+ if hw == "HEV":
175
+ self.eep = f"EEP_stHevFD{base}"
176
+ if self.message == "ABS_ESC_01_10ms":
177
+ self.eep = "EEP_stHevFDAbs01"
178
+ if self.message == "FPCM_01_100ms" :
179
+ self.eep = "EEP_stHevHSFpcm01"
180
+ if self.message == "SBCM_DRV_03_200ms":
181
+ self.eep = "EEP_stFDSBCMDRV03"
182
+ if self.message == "SBCM_DRV_FD_01_200ms":
183
+ self.eep = "EEP_stFDSBCMDRVFD01"
184
+ if self.message.startswith("EMS_CVVD"):
185
+ self.buffer = f"Can_{base}_Buf_A"
186
+ if (self.message.startswith('BMS') or self.message.startswith('LDC')) and len(self.message) == 4:
187
+ self.messageCountValid = f"Can_cVldMsgCt{base}"
188
+ self.aliveCountValid = f"Can_cVldAlvCt{base}"
189
+ self.crcValid = f"Can_cVldChks{base}"
190
+ self.eep = f"EEP_st48V{base}"
191
+ self.eepIndex = f"EEP_48V_DCAN{tag}"
192
+ if self.message.startswith('MHSG'):
193
+ self.messageCountValid = f"Can_cVldMsgCt{base}"
194
+ self.aliveCountValid = f"Can_cVldAlvCt{base}"
195
+ self.crcValid = f"Can_cVldChks{base}"
196
+ self.eep = f"EEP_st48V{base.replace('St', '')}"
197
+ self.eepIndex = f"EEP_48V_DCAN{tag}"
198
+ self.detectionEnable = f"CanD_cEnaDet{base.replace('St', '')}"
199
+ self.deveMsg = f"DEve_Can{base.replace('St', '')}Msg"
200
+ self.deveCrc = f"DEve_Can{base.replace('St', '')}Chks"
201
+ self.deveAlv = f"DEve_Can{base.replace('St', '')}Alv"
202
+ if self.message.startswith('CVVD'):
203
+ self.messageCountValid = f"Can_cVldMsgCnt{base}"
204
+ self.aliveCountValid = f"Can_cVldAlvCnt{base}"
205
+ self.crcValid = f"Can_cVldCRC{base}"
206
+ self.eep = f"EEP_st{tag}"
207
+ self.eepIndex = f"EEP_DCAN{tag}"
208
+ if self.message == "NOx1Down":
209
+ self.fid = "Fid_CanNOx1DownD"
210
+ self.deveMsg = "DEve_CanNOx1DownMsg"
211
+ self.eepIndex = f"EEP_DCAN{tag}"
212
+ if self.message == "NOx1Ext":
213
+ self.fid = "Fid_CanNOx1ExtD"
214
+ self.deveMsg = "DEve_CanNOx1ExtMsg"
215
+ self.eepIndex = f"EEP_DCAN{tag}"
216
+ if self.message == "ABS_ESC_01_10ms":
217
+ self.deveMsg = "DEve_FDAbs01Msg"
218
+ self.deveCrc = "DEve_FDAbs01Crc"
219
+ self.deveAlv = "DEve_FDAbs01Alv"
220
+ return
221
+
222
+ def __str__(self) -> str:
223
+ return self.message
224
+
225
+
226
+ if __name__ == "__main__":
227
+
228
+ rule = naming("FPCM_01_100ms")
229
+ print(rule.root)
File without changes
File without changes
@@ -0,0 +1,48 @@
1
+ from cannect.core.can.rule import naming
2
+ from cannect.core.testcase.unitcase import UnitTestCase
3
+ from pandas import DataFrame, Series
4
+
5
+
6
+ class Asw2CanUnit(UnitTestCase):
7
+
8
+ def __init__(self, sig:Series, io:DataFrame, **override):
9
+ nm = naming(sig)
10
+ unit = '-' if not sig.Unit else sig.Unit
11
+ model = io["module"].values[0]
12
+ path = io["Path"].values[0]
13
+
14
+ inputs = io[io["dir"] == 'input'].copy()
15
+ inputs.loc[inputs["value"].isna(), "value"] = "External"
16
+ outputs = io[io["dir"] == 'output'].copy()
17
+ var = ",".join([v for v in outputs["name"] if v.startswith(outputs["Signal"].values[0])])
18
+ o, c = '{', '}'
19
+ kwargs = {
20
+ "Category": "UNIT",
21
+ "Group": "CAN",
22
+ "Test Case Name": "Signal Interface Test",
23
+ "Test Purpose, Description": f"{sig.name} @{nm}({sig.ID}) Interface Test",
24
+ "Test Execution (TE) - Description": f"ENGINE ON/RUN\n"
25
+ f"- 차량 검증 시: 차량 주행에 따름\n"
26
+ f"- 정적 검증 시: 오프라인 SW 검증",
27
+ "TE-Variable": "\n".join(inputs["name"]),
28
+ "TE-Compare": "'" + "\n".join(["="] * len(inputs)),
29
+ "TE-Value": "\n".join(inputs["value"]),
30
+ "Expected Results (ER) - Description": f"정상 인터페이스\n"
31
+ f"- 로직 모델: %{model}{path}\n"
32
+ f"- CAN 신호 변수 = {var}\n"
33
+ f"신호 속성 DB 정합",
34
+ "ER-Variable": "\n".join(outputs["name"]),
35
+ "ER-Compare": "'" + "\n".join(["="] * len(outputs)),
36
+ "ER-Value": "\n".join(["Calculated"] * len(outputs)),
37
+ "Test Result Description": f"정상 인터페이스\n"
38
+ f"- {var} = {o}%{model}{path}{c}\n\n"
39
+ f"신호 속성\n"
40
+ f"- Factor: {sig.Factor}\n"
41
+ f"- Offset: {sig.Offset}\n"
42
+ f"- Min: {sig.Offset} [{unit}]\n"
43
+ f"- Max: {sig.Factor * (2 ** sig.Length - 1) + sig.Offset} [{unit}]\n"
44
+ f"* 차량 주행 시 Min/Max 검증 확인 불가" ,
45
+ }
46
+ kwargs.update(override)
47
+ super().__init__(**kwargs)
48
+ return