Skip to content

Commit 87f7b8b

Browse files
committed
Configuration.py support for Enable Safety Interlock
1 parent 5b39943 commit 87f7b8b

File tree

11 files changed

+231
-12
lines changed

11 files changed

+231
-12
lines changed

BS1200 Configuration.ini

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version='1.0' standalone='yes' ?>
2+
<GXML_Root>
3+
<GXML_Root>
4+
<CAN_Settings mems='5'>
5+
<interface_index type='U32'>0</interface_index>
6+
<baud_rate type='U32'>1000000</baud_rate>
7+
<receive_queue_size type='U32'>64</receive_queue_size>
8+
<box_ID type='U32'>1</box_ID>
9+
<write_period_ms type='I64'>5000</write_period_ms>
10+
</CAN_Settings>
11+
<HIL_Msg_IDs dim='[6]' type='U32'>
12+
<Msg_ID>128</Msg_ID>
13+
<Msg_ID>160</Msg_ID>
14+
<Msg_ID>176</Msg_ID>
15+
<Msg_ID>192</Msg_ID>
16+
<Msg_ID>512</Msg_ID>
17+
<Msg_ID>544</Msg_ID>
18+
</HIL_Msg_IDs>
19+
<PID_gains mems='3'>
20+
<proportional_gain type='DBL'>0.3</proportional_gain>
21+
<integral_gain type='DBL'>0.55</integral_gain>
22+
<derivative_gain type='DBL'>0</derivative_gain>
23+
</PID_gains>
24+
<Enable_Cell_Inhibit type='Bool'>FALSE</Enable_Cell_Inhibit>
25+
</GXML_Root>

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ BS1200 Configuration JSON object example:
120120
"CAN_Settings": {
121121
"Box_ID": 1,
122122
"Write_Period_ms": 5
123-
}
123+
},
124+
"Enable_SafetyInterlock" : false
124125
}
125126
```
126127
By default the methods used to set configuration values will restart the connected target using the NI System Configuration API. It is highly reccomended to restart the unit whenever updating values to prevent a desynchronization between the target IP address saved to class properties and currently used IP address of the device.

bs1200_cfg.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Protocol": "CAN", "IP_Address": "192.168.1.102", "Ethernet_Settings": {"TCP_Cmd_Port": "12345", "TCP_Cmd_Interval_ms": "20", "UDP_Read_Port": "54321", "UDP_Read_Interval_ms": "10"}, "CAN_Settings": {"Box_ID": 2, "Write_Period_ms": 5}, "Enable_SafetyInterlock" : true}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "BS1200_driver"
3-
version = "1.2.9"
3+
version = "1.2.10"
44
authors = [{ name = "Mikhail Kharitonov", email = "[email protected]"}]
55
description= "Python interface to the Bloomy BS1200"
66
readme = "README.md"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<GXML_Root>
2+
<CAN_Settings mems="5">
3+
<interface_index type="U32">0</interface_index>
4+
<baud_rate type="U32">1000000</baud_rate>
5+
<receive_queue_size type="U32">64</receive_queue_size>
6+
<box_ID type="U32">1</box_ID>
7+
<write_period_ms type="I64">5000</write_period_ms>
8+
</CAN_Settings>
9+
<HIL_Msg_IDs dim="[6]" type="U32">
10+
<Msg_ID>128</Msg_ID>
11+
<Msg_ID>160</Msg_ID>
12+
<Msg_ID>176</Msg_ID>
13+
<Msg_ID>192</Msg_ID>
14+
<Msg_ID>512</Msg_ID>
15+
<Msg_ID>544</Msg_ID>
16+
</HIL_Msg_IDs>
17+
<PID_gains mems="3">
18+
<proportional_gain type="DBL">0.3</proportional_gain>
19+
<integral_gain type="DBL">0.55</integral_gain>
20+
<derivative_gain type="DBL">0</derivative_gain>
21+
</PID_gains>
22+
<Enable_Cell_Inhibit type="Bool">FALSE</Enable_Cell_Inhibit>
23+
</GXML_Root>

src/bs1200/configuration.py

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ def apply_config_file(self, cfg_file_path, restart: bool = True):
4242
{
4343
"Box_ID" : 1,
4444
"Write_Period_ms" : 5
45-
}
45+
},
46+
"Enable_SafetyInterlock" : true
4647
}
4748
"""
4849
with open(cfg_file_path) as json_file:
@@ -55,14 +56,15 @@ def apply_config_file(self, cfg_file_path, restart: bool = True):
5556
config["Ethernet_Settings"]['TCP_Cmd_Interval_ms'],
5657
config["Ethernet_Settings"]['UDP_Read_Port'],
5758
config["Ethernet_Settings"]['UDP_Read_Interval_ms'])
59+
en_interlock = config["Enable_SafteyInterlock"]
5860
#print(mode)
5961
#print(can_cfg)
6062
#print(eth_cfg)
6163

6264
self.apply_general_settings(mode, False)
6365
self.apply_can_config(can_cfg, False)
6466
self.apply_ethernet_settings(eth_cfg, False)
65-
67+
self.enable_safety_interlock(en_interlock, False)
6668
if restart:
6769
self.__restart_unit()
6870

@@ -75,6 +77,7 @@ def get_all_settings(self, export_to_file: bool,
7577
ethernet = self.get_ethernet_settings()
7678
can = self.get_can_settings()
7779
mode = self.get_protocol()
80+
interlock = self.interlock_enabled()
7881
config = {'Protocol' : mode, 'IP_Address' : ethernet.IP_Address,
7982
'Ethernet_Settings':{
8083
'TCP_Cmd_Port' : ethernet.Command_Port,
@@ -86,7 +89,8 @@ def get_all_settings(self, export_to_file: bool,
8689
{
8790
'Box_ID' : can.box_id,
8891
'Write_Period_ms' : int(can.publish_period_us/1000)
89-
}
92+
},
93+
'Enable_SafetyInterlock' : interlock
9094
}
9195
if export_to_file:
9296
with open(file_name, 'w') as f:
@@ -165,12 +169,37 @@ def apply_can_config(self, can_cfg: CAN_Settings, restart: bool = True):
165169
if restart:
166170
self.__restart_unit()
167171

172+
def enable_safety_interlock(self, interlock, restart: bool = True):
173+
"""
174+
Enables or disables the BS1200 Safety Interlock feature
175+
"""
176+
rt_path = "/ni-rt/startup/Data/BS1200 Configuration.ini"
177+
temp_path = "BS1200 Configuration.ini"
178+
cfgfile_path = self.FTP.getFile(rt_path, temp_path)
179+
self.__fix_XML_tags(cfgfile_path)
180+
#build an XML tree for the .ini file 🤦‍♂️
181+
tree = ET.parse(cfgfile_path)
182+
root = tree.getroot()
183+
#Replace Enable_Cell_Inhibit
184+
root[3].text = "TRUE" if interlock else "FALSE"
185+
#Rewrite the temp config file
186+
tree.write(cfgfile_path, encoding="utf-8", xml_declaration=True, short_empty_elements=False)
187+
#replace the configuration file on the target
188+
self.__replace_xml_declaration(cfgfile_path)
189+
self.FTP.uploadFile(cfgfile_path, rt_path)
190+
os.remove(temp_path)
191+
#restart unit by default
192+
if restart:
193+
self.__restart_unit()
168194

169195
def set_ip_address(self, new_ip_address: str):
170196
"""
171197
Sets a new IP Address for the target BS1200, restarting the unit and updating
172198
the ip address used by the ConfigTools for further configuration method calls
173199
"""
200+
#no broadcast bytes allowed
201+
if("255" in new_ip_address):
202+
raise ValueError("Broadcast bytes are not allowed for the unit IP address")
174203
#get the ni-rt.ini file from the BS1200 controller root directory
175204
self.FTP.getFile('ni-rt.ini', 'ni-rt.ini')
176205
#open the local copy of the cfg file and set the IP Address parameter of the
@@ -247,7 +276,7 @@ def set_udp_settings(self, rep_port: int, rep_interval_ms: int):
247276
self.FTP.uploadFile(cfgfile_path, rt_path)
248277
os.remove(temp_path)
249278

250-
def get_can_settings(self) -> CAN_Settings:
279+
def get_can_settings(self):
251280
"""
252281
Retreive the can settings from the target BS1200
253282
"""
@@ -261,7 +290,7 @@ def get_can_settings(self) -> CAN_Settings:
261290
os.remove(temp_path)
262291
return CAN_Settings(int(root[0][3].text), int(root[0][4].text))
263292

264-
def get_ethernet_settings(self) -> Ethernet_Settings:
293+
def get_ethernet_settings(self):
265294
"""
266295
Retreive the ethernet settings and IP address from the target device
267296
"""
@@ -306,8 +335,23 @@ def get_ethernet_settings(self) -> Ethernet_Settings:
306335
os.remove(temp_path2)
307336
os.remove('ni-rt.ini')
308337
return Ethernet_Settings(ip, tcp_port, tcp_interval, udp_port, udp_interval)
338+
339+
def interlock_enabled(self):
340+
"""
341+
Retreive the state of the Safety Interlock from the target BS1200
342+
"""
343+
rt_path = "/ni-rt/startup/Data/BS1200 Configuration.ini"
344+
temp_path = "BS1200 Configuration.ini"
345+
cfgfile_path = self.FTP.getFile(rt_path, temp_path)
346+
self.__fix_XML_tags(cfgfile_path)
347+
#build an XML tree for the .ini file 🤦‍♂️
348+
tree = ET.parse(cfgfile_path)
349+
root = tree.getroot()
350+
os.remove(temp_path)
351+
return True if root[3].text == "TRUE" else False
352+
309353

310-
def get_protocol(self) -> str:
354+
def get_protocol(self):
311355
"""
312356
Get the procotol form the general settings
313357
"""
@@ -333,7 +377,7 @@ def __restart_unit(self):
333377
with nisyscfg.Session(self.ip_address, self.user, self.pwd) as s:
334378
#updates IP address for the ConfigTools instance to the new IP address once restart complete
335379
ev = self.__start_anim(f"Restarting BS1200 ({self.ip_address})... ")
336-
self.ip_address = self.ip_address = s.restart()
380+
self.ip_address = s.restart()
337381
ev.set()
338382
#do this again just in case
339383
self.FTP.tgt_address = self.ip_address

src/bs1200_cfg.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"Protocol": "CAN",
3+
"IP_Address": "192.168.1.102",
4+
"Ethernet_Settings": {
5+
"TCP_Cmd_Port": "12345",
6+
"TCP_Cmd_Interval_ms": "20",
7+
"UDP_Read_Port": "54321",
8+
"UDP_Read_Interval_ms": "10"
9+
},
10+
"CAN_Settings": {
11+
"Box_ID": 2,
12+
"Write_Period_ms": 5.5
13+
},
14+
"Enable_SafetyInterlock" : true
15+
}

src/classes.html

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<html>
2+
<body>
3+
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
4+
<div class="mermaid">
5+
6+
classDiagram
7+
class BS1200 {
8+
ai_v_output_txt : str
9+
box_ids : list
10+
buffer : BufferedReader
11+
bus : PcanBus
12+
cell_i_output_txt : str
13+
cell_v_output_txt : str
14+
notifier : Notifier
15+
ao_set(boxid: int, AO1_Voltage: float, AO2_Voltage: float) bool
16+
box_id_check(boxid) bool
17+
cell_enable(boxid: int, channel: int, status: bool)
18+
cell_enable_all(boxid: int, status: bool)
19+
channel_check(channel: int) bool
20+
close()
21+
config_can_publishing(boxid: int, dio_en: bool, ao_en: bool, ai_en: bool)
22+
dio_set(boxid: int, dio_dir: list, dio_en: list) bool
23+
hil_mode(boxid: int, enable_HIL: bool) bool
24+
query_system_status(boxid: int)
25+
readback_I_all(boxid: int) list
26+
readback_V_all(boxid) list
27+
readback_ai_all(boxid: int) list
28+
readback_ai_v(boxid: int, channel: int) float
29+
readback_cell_I(boxid: int, channel: int) float
30+
readback_cell_V(boxid: int, channel: int) float
31+
readback_dio(boxid) list
32+
scale_current(currentIn, to_eng_units: bool)
33+
scale_volts(voltsIn: float, to_eng_units: bool) float
34+
set_I_all(boxid: int, sink_i: float, source_i: float)
35+
set_V_all(boxid, tgt_volt: float)
36+
set_cell_I_sink(boxid: int, channel: int, sink_current: float) Message
37+
set_cell_I_source(boxid: int, channel: int, source_current: float) Message
38+
set_cell_V(boxid: int, channel: int, voltage: float) Message
39+
}
40+
class CAN_Settings {
41+
box_id : int
42+
publish_period_us : int
43+
}
44+
class ConfigTools {
45+
FTP
46+
ini_parser : ConfigParser
47+
ip_address : str
48+
pwd : str
49+
user : str
50+
apply_can_config(can_cfg: CAN_Settings, restart: bool)
51+
apply_config_file(cfg_file_path, restart: bool)
52+
apply_ethernet_settings(tcpip_cfg: Ethernet_Settings, restart: bool)
53+
apply_general_settings(protocol: Protocol, restart: bool)
54+
get_all_settings(export_to_file: bool, file_name: str) str
55+
get_can_settings() CAN_Settings
56+
get_ethernet_settings() Ethernet_Settings
57+
get_protocol() str
58+
set_ip_address(new_ip_address: str)
59+
set_tcp_settings(ip_address: str, cmd_port: int, cmd_interval_ms: int)
60+
set_udp_settings(rep_port: int, rep_interval_ms: int)
61+
}
62+
class Ethernet_Settings {
63+
Command_Interval_ms : int
64+
Command_Port : int
65+
IP_Address : str
66+
Reporting_Interval_ms : int
67+
Reporting_Port : int
68+
}
69+
class FtpHelper {
70+
password : str
71+
tgt_address : str
72+
username : str
73+
getFile(tgt_path, dest_path) str
74+
uploadFile(src_path, tgt_path)
75+
}
76+
class Protocol {
77+
CAN : int
78+
Ethernet : int
79+
}
80+
FtpHelper --* ConfigTools : FTP
81+
82+
</div>
83+
</body>
84+
</html>

src/packages.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<html>
2+
<body>
3+
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
4+
<div class="mermaid">
5+
6+
classDiagram
7+
class bs1200 {
8+
}
9+
class can_frames {
10+
}
11+
class cfg_tools {
12+
}
13+
class configuration {
14+
}
15+
class driver {
16+
}
17+
bs1200 --> cfg_tools
18+
bs1200 --> configuration
19+
bs1200 --> driver
20+
configuration --> cfg_tools
21+
driver --> can_frames
22+
23+
</div>
24+
</body>
25+
</html>

tests/bs1200_cfg.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
{
1313
"Box_ID" : 1,
1414
"Write_Period_ms" : 5
15-
}
15+
},
16+
"Enable_SafetyInterlock" : true
1617
}

0 commit comments

Comments
 (0)