10
10
from datetime import datetime , timedelta
11
11
import xml .etree .ElementTree as ET
12
12
13
- from acd .exceptions .CompsRecordException import UnknownRxTagVersion
14
13
from acd .generated .comps .rx_generic import RxGeneric
15
- from acd .generated .comps .rx_tag import RxTag
16
- from acd .generated .controller .rx_controller import RxController
17
- from acd .generated .map_device .rx_map_device import RxMapDevice
18
14
15
+ from loguru import logger as log
19
16
20
17
@dataclass
21
18
class L5xElementBuilder :
@@ -39,7 +36,7 @@ def to_xml(self):
39
36
if isinstance (attribute_value , L5xElement ):
40
37
child_list .append (attribute_value .to_xml ())
41
38
elif isinstance (attribute_value , list ):
42
- if attribute == "tags" or attribute == "data_types" or attribute == "members" :
39
+ if attribute == "tags" or attribute == "data_types" or attribute == "members" or attribute == "programs" or attribute == "routines" :
43
40
new_child_list : List [str ] = []
44
41
for element in attribute_value :
45
42
if isinstance (element , L5xElement ):
@@ -99,6 +96,8 @@ class MapDevice(L5xElement):
99
96
100
97
@dataclass
101
98
class Routine (L5xElement ):
99
+ name : str
100
+ type : str
102
101
rungs : List [str ]
103
102
104
103
@@ -137,7 +136,7 @@ class RSLogix5000Content(L5xElement):
137
136
schema_revision : str
138
137
software_revision : str
139
138
target_name : str
140
- target_name : str
139
+ target_type : str
141
140
contains_context : str
142
141
export_date : str
143
142
export_options : str
@@ -336,16 +335,16 @@ def build(self) -> Tag:
336
335
except Exception as e :
337
336
return Tag (results [0 ][0 ], results [0 ][0 ], "Base" , "" , "Decimal" , "None" , 0 , [])
338
337
339
- if r .cip_type != 0x6B :
338
+ if r .cip_type != 0x6B and r . cip_type != 0x68 :
340
339
return Tag (results [0 ][0 ], results [0 ][0 ], "Base" , "" , "Decimal" , "None" , 0 , [])
341
340
if r .main_record .data_type == 0xFFFFFFFF :
342
- return Tag ( results [ 0 ][ 0 ], results [ 0 ][ 0 ], "Base" , "" , "Decimal" , "None" , r . main_record . data_table_instance , [])
343
-
344
- self ._cur .execute (
345
- "SELECT comp_name, object_id, parent_id, record FROM comps WHERE object_id=" + str (
346
- r .main_record .data_type ))
347
- data_type_results = self ._cur .fetchall ()
348
- data_type = data_type_results [0 ][0 ]
341
+ data_type = ""
342
+ else :
343
+ self ._cur .execute (
344
+ "SELECT comp_name, object_id, parent_id, record FROM comps WHERE object_id=" + str (
345
+ r .main_record .data_type ))
346
+ data_type_results = self ._cur .fetchall ()
347
+ data_type = data_type_results [0 ][0 ]
349
348
350
349
self ._cur .execute (
351
350
"SELECT tag_reference, record_string FROM comments WHERE parent=" + str (
@@ -372,6 +371,24 @@ def build(self) -> Tag:
372
371
return Tag (name , name , "Base" , data_type , radix , external_access , r .main_record .data_table_instance , comment_results )
373
372
374
373
374
+ def routine_type_enum (idx : int ) -> str :
375
+ if idx == 0 :
376
+ return "TypeLess"
377
+ if idx == 1 :
378
+ return "RLL"
379
+ if idx == 2 :
380
+ return "FBD"
381
+ if idx == 3 :
382
+ return "SFC"
383
+ if idx == 4 :
384
+ return "ST"
385
+ if idx == 5 :
386
+ return "External"
387
+ if idx == 6 :
388
+ return "Encrypted"
389
+ return "Typeless"
390
+
391
+
375
392
@dataclass
376
393
class RoutineBuilder (L5xElementBuilder ):
377
394
@@ -381,8 +398,14 @@ def build(self) -> Routine:
381
398
self ._object_id ))
382
399
results = self ._cur .fetchall ()
383
400
401
+ try :
402
+ r = RxGeneric .from_bytes (results [0 ][3 ])
403
+ except Exception as e :
404
+ return Routine (results [0 ][0 ], results [0 ][0 ], "" , [])
405
+
384
406
record = results [0 ][3 ]
385
407
name = results [0 ][0 ]
408
+ routine_type = routine_type_enum (struct .unpack_from ("<H" , r .record_buffer , 0x30 )[0 ])
386
409
387
410
self ._cur .execute (
388
411
"SELECT object_id, parent_id, seq_no FROM region_map WHERE parent_id=" + str (
@@ -396,7 +419,7 @@ def build(self) -> Routine:
396
419
rungs_results = self ._cur .fetchall ()
397
420
if len (rungs_results ) > 0 :
398
421
rungs .append (rungs_results [0 ][1 ])
399
- return Routine (name , rungs )
422
+ return Routine (name , name , routine_type , rungs )
400
423
401
424
402
425
@dataclass
@@ -459,6 +482,8 @@ def build(self) -> Program:
459
482
self ._object_id ))
460
483
results = self ._cur .fetchall ()
461
484
485
+ r = RxGeneric .from_bytes (results [0 ][3 ])
486
+
462
487
name = results [0 ][0 ]
463
488
464
489
self ._cur .execute (
@@ -492,6 +517,11 @@ def build(self) -> Program:
492
517
for result in results :
493
518
tags .append (TagBuilder (self ._cur , result [1 ]).build ())
494
519
520
+ self ._cur .execute (
521
+ "SELECT tag_reference, record_string FROM comments WHERE parent=" + str (
522
+ (r .comment_id * 0x10000 ) + r .cip_type ))
523
+ comment_results = self ._cur .fetchall ()
524
+
495
525
return Program (name , routines , tags )
496
526
497
527
@@ -641,14 +671,14 @@ def build(self) -> RSLogix5000Content:
641
671
now = datetime .now ()
642
672
export_date = now .strftime ("%a %b %d %H:%M:%S %Y" )
643
673
export_options = "NoRawData L5KData DecoratedData ForceProtectedEncoding AllProjDocTrans"
644
- return RSLogix5000Content (None , schema_revision , software_revision , target_name , target_type , contains_context , export_date , export_options )
674
+ return RSLogix5000Content (target_name , None , schema_revision , software_revision , target_name , target_type , contains_context , export_date , export_options )
645
675
646
676
647
677
@dataclass
648
678
class DumpCompsRecords (L5xElementBuilder ):
649
679
base_directory : PathLike = Path ("dump" )
650
680
651
- def dump (self , parent_id : int = 0 ):
681
+ def dump (self , parent_id : int = 0 , log_file = None ):
652
682
self ._cur .execute (
653
683
f"SELECT comp_name, object_id, parent_id, record_type, record FROM comps WHERE parent_id={ parent_id } " )
654
684
results = self ._cur .fetchall ()
@@ -663,8 +693,8 @@ def dump(self, parent_id: int = 0):
663
693
if not os .path .exists (os .path .join (new_path )):
664
694
os .makedirs (new_path )
665
695
with open (Path (os .path .join (new_path , name + ".dat" )), "wb" ) as file :
696
+ log_file .write (
697
+ f"Class - { struct .unpack_from ('<H' , result [4 ], 0xA )[0 ]} Instance { struct .unpack_from ('<H' , result [4 ], 0xC )[0 ]} - { str (new_path ) + '/' + name } \n " )
666
698
file .write (record )
667
699
668
- DumpCompsRecords (self ._cur , object_id , new_path ).dump (object_id )
669
-
670
-
700
+ DumpCompsRecords (self ._cur , object_id , new_path ).dump (object_id , log_file )
0 commit comments