Skip to content

Commit 625ff12

Browse files
committed
fix: created generic parsing of fields
1 parent 58920fc commit 625ff12

File tree

9 files changed

+528
-86
lines changed

9 files changed

+528
-86
lines changed

acd/api.py

+8-10
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,31 @@
11
from dataclasses import dataclass
22
from os import PathLike
3+
from typing import List
34

45
from acd.database.acd_database import AcdDatabase
5-
from acd.l5x.elements import Controller, DumpCompsRecords
6+
from acd.l5x.elements import Controller, DumpCompsRecords, RSLogix5000Content
67

78
from acd.export_l5x import ExportL5x
89
from acd.unzip import Unzip
910

1011

1112
# Returned Project Structures
12-
@dataclass
13-
class Project:
14-
"""Controller Project"""
15-
controller: Controller
13+
1614

1715

1816
# Import Export Interfaces
1917
class ImportProject:
2018
""""Interface to import an PLC project"""
2119

22-
def import_project(self) -> Project:
20+
def import_project(self) -> RSLogix5000Content:
2321
# Import Project Interface
2422
pass
2523

2624

2725
class ExportProject:
2826
""""Interface to export an PLC project"""
2927

30-
def export_project(self, project: Project):
28+
def export_project(self, project: RSLogix5000Content):
3129
# Export Project Interface
3230
pass
3331

@@ -38,18 +36,18 @@ class ImportProjectFromFile(ImportProject):
3836
"""Import a Controller from an ACD stored on file"""
3937
filename: PathLike
4038

41-
def import_project(self) -> Project:
39+
def import_project(self) -> RSLogix5000Content:
4240
# Import Project Interface
4341
export = ExportL5x(self.filename)
44-
return Project(export.controller)
42+
return export.project
4543

4644

4745
@dataclass
4846
class ExportProjectToFile(ExportProject):
4947
"""Export a Controller to an ACD file"""
5048
filename: PathLike
5149

52-
def export_project(self, project: Project):
50+
def export_project(self, project: RSLogix5000Content):
5351
# Concreate example of exporting a Project Object to an ACD file
5452
raise NotImplementedError
5553

acd/export_l5x.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
import struct
55
import tempfile
66
from dataclasses import dataclass, field
7+
from datetime import datetime
78
from sqlite3 import Cursor
9+
import xml.etree.ElementTree as ET
810

911
from acd.comments import CommentsRecord
1012
from acd.comps import CompsRecord
1113
from acd.dbextract import DbExtract
12-
from acd.l5x.elements import Controller, ControllerBuilder
14+
from acd.l5x.elements import Controller, ControllerBuilder, ProjectBuilder, RSLogix5000Content
1315
from acd.nameless import NamelessRecord
1416
from acd.sbregion import SbRegionRecord
1517
from acd.unzip import Unzip
@@ -21,6 +23,7 @@ class ExportL5x:
2123
input_filename: os.PathLike
2224
_temp_dir: str = "build" #tempfile.mkdtemp()
2325
_controller: Controller = None
26+
_project: RSLogix5000Content = None
2427

2528
def __post_init__(self):
2629
log.info("Creating temporary directory (if it doesn't exist to store ACD database files - " + self._temp_dir)
@@ -98,6 +101,13 @@ def controller(self):
98101
self._controller = ControllerBuilder(self._cur).build()
99102
return self._controller
100103

104+
@property
105+
def project(self):
106+
if self._project is None:
107+
self._project = ProjectBuilder(os.path.join(self._temp_dir, 'QuickInfo.XML')).build()
108+
self._project.controller = self.controller
109+
return self._project
110+
101111

102112
def populate_region_map(self):
103113
self._cur.execute(

acd/generated/comps/rx_generic.py

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
2+
3+
import kaitaistruct
4+
from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO
5+
6+
7+
if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 9):
8+
raise Exception("Incompatible Kaitai Struct Python API: 0.9 or later is required, but you have %s" % (kaitaistruct.__version__))
9+
10+
class RxGeneric(KaitaiStruct):
11+
def __init__(self, _io, _parent=None, _root=None):
12+
self._io = _io
13+
self._parent = _parent
14+
self._root = _root if _root else self
15+
self._read()
16+
17+
def _read(self):
18+
self.parent_id = self._io.read_u4le()
19+
self.unique_tag_identifier = self._io.read_u4le()
20+
self.record_format_version = self._io.read_u2le()
21+
self.cip_type = self._io.read_u2le()
22+
self.comment_id = self._io.read_u2le()
23+
_on = self.cip_type
24+
if _on == 107:
25+
self._raw_main_record = self._io.read_bytes(60)
26+
_io__raw_main_record = KaitaiStream(BytesIO(self._raw_main_record))
27+
self.main_record = RxGeneric.RxTag(_io__raw_main_record, self, self._root)
28+
else:
29+
self._raw_main_record = self._io.read_bytes(60)
30+
_io__raw_main_record = KaitaiStream(BytesIO(self._raw_main_record))
31+
self.main_record = RxGeneric.Unknown(_io__raw_main_record, self, self._root)
32+
self.len_record = self._io.read_u4le()
33+
self.count_record = self._io.read_u4le()
34+
self.extended_records = []
35+
for i in range((self.count_record - 1)):
36+
self.extended_records.append(RxGeneric.AttributeRecord(self._io, self, self._root))
37+
38+
self.last_extended_record = RxGeneric.LastAttributeRecord(self._io, self, self._root)
39+
40+
class Unknown(KaitaiStruct):
41+
def __init__(self, _io, _parent=None, _root=None):
42+
self._io = _io
43+
self._parent = _parent
44+
self._root = _root if _root else self
45+
self._read()
46+
47+
def _read(self):
48+
self.body = self._io.read_bytes(60)
49+
50+
51+
class LastAttributeRecord(KaitaiStruct):
52+
def __init__(self, _io, _parent=None, _root=None):
53+
self._io = _io
54+
self._parent = _parent
55+
self._root = _root if _root else self
56+
self._read()
57+
58+
def _read(self):
59+
self.attribute_id = self._io.read_u4le()
60+
self.record_length = self._io.read_u4le()
61+
self.value = self._io.read_bytes((self.record_length - 4))
62+
63+
64+
class RxMapDevice(KaitaiStruct):
65+
def __init__(self, _io, _parent=None, _root=None):
66+
self._io = _io
67+
self._parent = _parent
68+
self._root = _root if _root else self
69+
self._read()
70+
71+
def _read(self):
72+
pass
73+
74+
@property
75+
def module_id(self):
76+
if hasattr(self, '_m_module_id'):
77+
return self._m_module_id
78+
79+
_pos = self._io.pos()
80+
self._io.seek(36)
81+
self._m_module_id = self._io.read_u4le()
82+
self._io.seek(_pos)
83+
return getattr(self, '_m_module_id', None)
84+
85+
@property
86+
def product_type(self):
87+
if hasattr(self, '_m_product_type'):
88+
return self._m_product_type
89+
90+
_pos = self._io.pos()
91+
self._io.seek(4)
92+
self._m_product_type = self._io.read_u2le()
93+
self._io.seek(_pos)
94+
return getattr(self, '_m_product_type', None)
95+
96+
@property
97+
def vendor_id(self):
98+
if hasattr(self, '_m_vendor_id'):
99+
return self._m_vendor_id
100+
101+
_pos = self._io.pos()
102+
self._io.seek(2)
103+
self._m_vendor_id = self._io.read_u2le()
104+
self._io.seek(_pos)
105+
return getattr(self, '_m_vendor_id', None)
106+
107+
@property
108+
def slot_no(self):
109+
if hasattr(self, '_m_slot_no'):
110+
return self._m_slot_no
111+
112+
_pos = self._io.pos()
113+
self._io.seek(32)
114+
self._m_slot_no = self._io.read_u4le()
115+
self._io.seek(_pos)
116+
return getattr(self, '_m_slot_no', None)
117+
118+
@property
119+
def product_code(self):
120+
if hasattr(self, '_m_product_code'):
121+
return self._m_product_code
122+
123+
_pos = self._io.pos()
124+
self._io.seek(6)
125+
self._m_product_code = self._io.read_u2le()
126+
self._io.seek(_pos)
127+
return getattr(self, '_m_product_code', None)
128+
129+
@property
130+
def parent_module(self):
131+
if hasattr(self, '_m_parent_module'):
132+
return self._m_parent_module
133+
134+
_pos = self._io.pos()
135+
self._io.seek(22)
136+
self._m_parent_module = self._io.read_u4le()
137+
self._io.seek(_pos)
138+
return getattr(self, '_m_parent_module', None)
139+
140+
141+
class RxTag(KaitaiStruct):
142+
def __init__(self, _io, _parent=None, _root=None):
143+
self._io = _io
144+
self._parent = _parent
145+
self._root = _root if _root else self
146+
self._read()
147+
148+
def _read(self):
149+
pass
150+
151+
@property
152+
def cip_data_type(self):
153+
if hasattr(self, '_m_cip_data_type'):
154+
return self._m_cip_data_type
155+
156+
_pos = self._io.pos()
157+
self._io.seek(52)
158+
self._m_cip_data_type = self._io.read_u2le()
159+
self._io.seek(_pos)
160+
return getattr(self, '_m_cip_data_type', None)
161+
162+
@property
163+
def data_type(self):
164+
if hasattr(self, '_m_data_type'):
165+
return self._m_data_type
166+
167+
_pos = self._io.pos()
168+
self._io.seek(28)
169+
self._m_data_type = self._io.read_u4le()
170+
self._io.seek(_pos)
171+
return getattr(self, '_m_data_type', None)
172+
173+
@property
174+
def dimension_2(self):
175+
if hasattr(self, '_m_dimension_2'):
176+
return self._m_dimension_2
177+
178+
_pos = self._io.pos()
179+
self._io.seek(16)
180+
self._m_dimension_2 = self._io.read_u4le()
181+
self._io.seek(_pos)
182+
return getattr(self, '_m_dimension_2', None)
183+
184+
@property
185+
def dimension_3(self):
186+
if hasattr(self, '_m_dimension_3'):
187+
return self._m_dimension_3
188+
189+
_pos = self._io.pos()
190+
self._io.seek(20)
191+
self._m_dimension_3 = self._io.read_u4le()
192+
self._io.seek(_pos)
193+
return getattr(self, '_m_dimension_3', None)
194+
195+
@property
196+
def valid(self):
197+
if hasattr(self, '_m_valid'):
198+
return self._m_valid
199+
200+
self._m_valid = True
201+
return getattr(self, '_m_valid', None)
202+
203+
@property
204+
def dimension_1(self):
205+
if hasattr(self, '_m_dimension_1'):
206+
return self._m_dimension_1
207+
208+
_pos = self._io.pos()
209+
self._io.seek(12)
210+
self._m_dimension_1 = self._io.read_u4le()
211+
self._io.seek(_pos)
212+
return getattr(self, '_m_dimension_1', None)
213+
214+
@property
215+
def data_table_instance(self):
216+
if hasattr(self, '_m_data_table_instance'):
217+
return self._m_data_table_instance
218+
219+
_pos = self._io.pos()
220+
self._io.seek(36)
221+
self._m_data_table_instance = self._io.read_u4le()
222+
self._io.seek(_pos)
223+
return getattr(self, '_m_data_table_instance', None)
224+
225+
226+
class AttributeRecord(KaitaiStruct):
227+
def __init__(self, _io, _parent=None, _root=None):
228+
self._io = _io
229+
self._parent = _parent
230+
self._root = _root if _root else self
231+
self._read()
232+
233+
def _read(self):
234+
self.attribute_id = self._io.read_u4le()
235+
self.record_length = self._io.read_u4le()
236+
self.value = self._io.read_bytes(self.record_length)
237+
238+
239+

0 commit comments

Comments
 (0)